﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Be alaways javaing...-随笔分类-J2SE</title><link>http://www.blogjava.net/byrtiger/category/32561.html</link><description>Loving Java</description><language>zh-cn</language><lastBuildDate>Tue, 16 Dec 2008 06:15:00 GMT</lastBuildDate><pubDate>Tue, 16 Dec 2008 06:15:00 GMT</pubDate><ttl>60</ttl><item><title>Agile</title><link>http://www.blogjava.net/byrtiger/archive/2008/12/16/246549.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Tue, 16 Dec 2008 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/12/16/246549.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/246549.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/12/16/246549.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/246549.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/246549.html</trackback:ping><description><![CDATA[<img src="http://www.blogjava.net/images/blogjava_net/byrtiger/agile.png" alt="" border="0" /><br />
<img src ="http://www.blogjava.net/byrtiger/aggbug/246549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-12-16 09:37 <a href="http://www.blogjava.net/byrtiger/archive/2008/12/16/246549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java面试题</title><link>http://www.blogjava.net/byrtiger/archive/2008/12/03/244078.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Wed, 03 Dec 2008 01:57:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/12/03/244078.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/244078.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/12/03/244078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/244078.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/244078.html</trackback:ping><description><![CDATA[刚刚找到的面试题目。自己做了一下，反正挺惨不人睹的。贴出来就想帮帮有需要的人 <br />
并且问问为什么是这个结果呢？有的题的答案真的想不到啊～想不到～ <br />
<br />
一、判断题（30分） <br />
1．Java程序里,创建新的类对象用关键字new，回收无用的类对象使用关键字free。 <br />
2．对象可以赋值，只要使用赋值号（等号）即可，相当于生成了一个各属性与赋值对象相同的新对象。 <br />
3．有的类定义时可以不定义构造函数，所以构造函数不是必需的。 <br />
4．类及其属性、方法可以同时有一个以上的修饰符来修饰。 <br />
5．Java的屏幕坐标是以像素为单位，容器的左下角被确定为坐标的起点 <br />
6．抽象方法必须在抽象类中，所以抽象类中的方法都必须是抽象方法。 <br />
7．Final类中的属性和方法都必须被final修饰符修饰。 <br />
8．最终类不能派生子类，最终方法不能被覆盖。 <br />
9．子类要调用父类的方法，必须使用super关键字。 <br />
10．一个Java类可以有多个父类。 <br />
11．如果p是父类Parent的对象，而c是子类Child的对象，则语句c = p是正确的。 <br />
12．在java集合中，Vector和HashMap是线程安全的。 <br />
13．当一个方法在运行过程中产生一个异常，则这个方法会终止，但是整个程序不一定终止运行。 <br />
14．接口是特殊的类，所以接口也可以继承，子接口将继承父接口的所有常量和抽象方法。 <br />
15．用&#8220;+&#8221;可以实现字符串的拼接，用- 可以从一个字符串中去除一个字符子串。 <br />
<br />
二、选择题（30分） <br />
1、关于垃圾收集的哪些叙述是正确的（&nbsp;&nbsp; ）： <br />
A．程序开发者必须自己创建一个线程进行内存释放的工作 <br />
B．垃圾收集允许程序开发者明确指定并立即释放该内存 <br />
C．垃圾收集将检查并释放不再使用的内存 <br />
D．垃圾收集能够在期望的时间释放被java对象使用的内存 <br />
2、下面的哪些赋值语句是不正确的（&nbsp;&nbsp; ）： <br />
A．float　f=11.1; <br />
B．double　d=5.3E12; <br />
C．double　d=3.14159; <br />
D．double　d=3.14D； <br />
3、下面关于变量及其范围的陈述哪些是不正确的（&nbsp;&nbsp; ）： <br />
A．实例变量是类的成员变量 <br />
B．实例变量用关键字static声明 <br />
C．在方法中定义的局部变量在该方法被执行时创建 <br />
D．局部变量在使用前必须被初始化 <br />
4、下列关于修饰符混用的说法，错误的是（&nbsp; ）： <br />
A．abstract不能与final并列修饰同一个类 <br />
B．abstract类中不可以有private的成员 <br />
C．abstract方法必须在abstract类中 <br />
D．static方法中能处理非static的属性 <br />
5、容器Panel和Applet缺省使用的布局编辑策略是（&nbsp;&nbsp;&nbsp; ）： <br />
A、BorderLayout&nbsp; B、FlowLayout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C、GridLayout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D、CardLayout <br />
6、以下标识符中哪项是不合法的(&nbsp;&nbsp;&nbsp; )： <br />
A、 BigMeaninglessName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B、$int <br />
C、1 st&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D、$1 <br />
7、main方法是Java&nbsp; Application程序执行的入口点，关于main方法的方法头以下哪项是合法的（&nbsp;&nbsp;&nbsp; ）： <br />
A、&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; void&nbsp; main（）&nbsp;&nbsp;&nbsp; <br />
B、&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; void&nbsp;&nbsp; main（String[ ]&nbsp; args） <br />
C、&nbsp;&nbsp;&nbsp; public&nbsp; static int&nbsp; main（String[ ]&nbsp; arg） <br />
D、&nbsp;&nbsp;&nbsp; public&nbsp; void&nbsp; main（String&nbsp; arg[ ]） <br />
8、执行完以下代码int [ ]&nbsp; x = new&nbsp; int[25]；后，以下哪项说明是正确的（&nbsp;&nbsp;&nbsp; ）： <br />
A、&nbsp;&nbsp;&nbsp; x[24]为0 <br />
B、&nbsp;&nbsp;&nbsp; x[24]未定义 <br />
C、&nbsp;&nbsp;&nbsp; x[25]为0 <br />
D、&nbsp;&nbsp;&nbsp; x[0]为空 <br />
9、以下代码段执行后的输出结果为（&nbsp;&nbsp;&nbsp;&nbsp; ）： <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp; x=3； int&nbsp; y=10； <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(y%x); <br />
A、0 <br />
B、1 <br />
C、2 <br />
D、3 <br />
10、以下哪个表达式是不合法的（&nbsp;&nbsp;&nbsp; ）： <br />
A、String&nbsp; x=&#8221;Hello&#8221;;&nbsp;&nbsp; int&nbsp; y=9;&nbsp;&nbsp; x+=y; <br />
B、String&nbsp; x=&#8221;Hello&#8221;;&nbsp;&nbsp; int&nbsp; y=9;&nbsp; if(x= =y)&nbsp; { } <br />
C、String&nbsp; x=&#8221;Hello&#8221;;&nbsp; int&nbsp; y=9;&nbsp; x=x+y; <br />
D、String&nbsp; x=null;&nbsp; int&nbsp; y=(x!=null)&amp;&amp;(x.length()&gt;0) ? x.length : 0 <br />
11、编译运行以下程序后，关于输出结果的说明正确的是 （&nbsp;&nbsp;&nbsp; ）： <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp; class&nbsp;&nbsp; Conditional{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; void&nbsp; main(String&nbsp; args[&nbsp; ]){ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp; x=4; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;value&nbsp; is&nbsp; &#8220;+ ((x&gt;4) ? 99.9 :9)); <br />
} <br />
} <br />
A、&nbsp;&nbsp;&nbsp; 输出结果为：value&nbsp; is&nbsp; 99.99 <br />
B、&nbsp;&nbsp;&nbsp; 输出结果为：value&nbsp; is&nbsp; 9 <br />
C、&nbsp;&nbsp;&nbsp; 输出结果为：value&nbsp; is&nbsp; 9.0 <br />
D、&nbsp;&nbsp;&nbsp; 编译错误 <br />
12、以下声明合法的是（&nbsp;&nbsp;&nbsp;&nbsp; ）： <br />
A、&nbsp;&nbsp;&nbsp; default&nbsp; String&nbsp; s； <br />
B、&nbsp;&nbsp;&nbsp; public&nbsp; final&nbsp; static&nbsp; native&nbsp; int&nbsp; w( ) <br />
C、&nbsp;&nbsp;&nbsp; abstract&nbsp; double&nbsp; d； <br />
D、&nbsp;&nbsp;&nbsp; abstract&nbsp; final&nbsp; double&nbsp; hyperbolicCosine( ) <br />
13、关于以下application的说明，正确的是（&nbsp;&nbsp;&nbsp; ）： <br />
1．&nbsp; class&nbsp;&nbsp; StaticStuff <br />
2． { <br />
3．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static&nbsp; int&nbsp; x=10； <br />
4．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static&nbsp; { x+=5；} <br />
5．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; void&nbsp; main（String&nbsp; args[ ]） <br />
6．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
7．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;x=&#8221; + x); <br />
8．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
9．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static&nbsp; { x/=3;} <br />
10.&nbsp;&nbsp; } <br />
A、 4行与9行不能通过编译，因为缺少方法名和返回类型&nbsp; <br />
B、 9行不能通过编译，因为只能有一个静态初始化器 <br />
C、 编译通过，执行结果为：x=5 <br />
D、编译通过，执行结果为：x=3 <br />
14、关于以下程序代码的说明正确的是（&nbsp;&nbsp; ）： <br />
1．class&nbsp; HasStatic{ <br />
2．&nbsp;&nbsp;&nbsp; private&nbsp; static&nbsp; int&nbsp; x=100； <br />
3．&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; void&nbsp; main(String&nbsp; args[&nbsp; ]){ <br />
4．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HasStatic&nbsp; hs1=new&nbsp; HasStatic(&nbsp; ); <br />
5．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hs1.x++; <br />
6．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HasStatic&nbsp; hs2=new&nbsp; HasStatic(&nbsp; ); <br />
7．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hs2.x++; <br />
8．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hs1=new&nbsp; HasStatic( ); <br />
9．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hs1.x++; <br />
10．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HasStatic.x- -; <br />
11．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;x=&#8221;+x); <br />
12．&nbsp;&nbsp; } <br />
13．} <br />
A、5行不能通过编译，因为引用了私有静态变量 <br />
B、10行不能通过编译，因为x是私有静态变量 <br />
C、程序通过编译，输出结果为：x=103 <br />
D、程序通过编译，输出结果为：x=102 <br />
15、以下选项中循环结构合法的是（&nbsp;&nbsp;&nbsp; ）： <br />
A、while (int&nbsp; i&lt;7){ <br />
&nbsp;&nbsp;&nbsp;&nbsp; i++; <br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;i is &#8220;+i); <br />
} <br />
B、int&nbsp; j=3; <br />
while(j){ <br />
&nbsp;&nbsp; System.out.println(&#8220; j&nbsp; is &#8220;+j); <br />
} <br />
C、int&nbsp; j=0; <br />
for(int&nbsp; k=0; j + k !=10; j++,k++){ <br />
&nbsp;&nbsp;&nbsp; System.out.println(&#8220; j&nbsp; is &#8220;+ j + &#8220;k&nbsp; is&#8221;+ k); <br />
} <br />
D、int&nbsp; j=0; <br />
do{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( &#8220;j&nbsp; is &#8220;+j++); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (j = = 3) {continue&nbsp; loop;} <br />
}while&nbsp; (j&lt;10); <br />
<br />
三、简答题（40分） <br />
1.&nbsp;&nbsp;&nbsp; 写出下列程序的运行结果 <br />
public class Cat <br />
{　　 <br />
&nbsp; void mi( ) throws NullPointerException <br />
&nbsp; { <br />
&nbsp;&nbsp;&nbsp; System.out.println( &#8220;Cat mi mi .. &#8220; ); <br />
&nbsp; } <br />
} <br />
public class SmallCat extends Cat <br />
{int i=8; <br />
&nbsp; void mi( ) throws Exception <br />
&nbsp; { <br />
&nbsp;&nbsp;&nbsp; System.out.println( &#8220;SmallCat mi mi .. &#8220; ); <br />
&nbsp; } <br />
&nbsp; public static void main( String[] a ) throws Exception <br />
&nbsp; { <br />
&nbsp;&nbsp;&nbsp; Cat cat = new SmallCat(); <br />
&nbsp;&nbsp;&nbsp; cat.mi(); <br />
&nbsp; } <br />
} <br />
<br />
<br />
写出下列程序的运行结果 <br />
interface Playable { <br />
&nbsp;&nbsp;&nbsp; void play(); <br />
} <br />
interface Bounceable { <br />
&nbsp;&nbsp;&nbsp; void play(); <br />
} <br />
interface Rollable extends Playable, Bounceable { <br />
&nbsp;&nbsp;&nbsp; Ball ball = new Ball("PingPang"); <br />
} <br />
class Ball implements Rollable { <br />
&nbsp;&nbsp;&nbsp; private String name; <br />
&nbsp;&nbsp;&nbsp; public String getName() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return name; <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; public Ball(String name) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.name = name;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp; public void play() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ball = new Ball("Football"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ball.getName()); <br />
&nbsp;&nbsp;&nbsp; } <br />
} <br />
<br />
写出下列程序的运行结果 <br />
class Value{ <br />
public int i = 15; <br />
} <br />
public class Test{ <br />
public static void main(String argv[]){ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test t = new Test(); <br />
&nbsp;&nbsp;&nbsp; t.first(); <br />
&nbsp;&nbsp; } <br />
public void first(){ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 5; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Value v = new Value(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v.i = 25; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; second(v, i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(v.i); <br />
&nbsp;&nbsp; } <br />
public void second(Value v, int i){ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = 0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v.i = 20; <br />
&nbsp;&nbsp;&nbsp;&nbsp; Value val = new Value(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v = val; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(v.i + " " + i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
} <br />
<br />
<br />
写出下列程序的运行结果 <br />
class MyThread extends Thread{ <br />
public void run(){ <br />
System.out.println("MyThread: run()"); <br />
} <br />
public void start(){ <br />
System.out.println("MyThread: start()"); <br />
&nbsp;&nbsp;&nbsp; } <br />
} <br />
class MyRunnable implements Runnable{ <br />
public void run(){ <br />
System.out.println("MyRunnable: run()"); <br />
&nbsp;&nbsp;&nbsp; } <br />
public void start(){ <br />
System.out.println("MyRunnable: start()"); <br />
&nbsp;&nbsp; } <br />
} <br />
public class MyTest { <br />
public static void main(String args[]){ <br />
MyThread myThread&nbsp; =&nbsp; new MyThread(); <br />
MyRunnable myRunnable = new MyRunnable(); <br />
Thread thread&nbsp; =&nbsp; new Thread(myRunnable); <br />
myThread.start(); <br />
thread.start(); <br />
} <br />
} 
<img src ="http://www.blogjava.net/byrtiger/aggbug/244078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-12-03 09:57 <a href="http://www.blogjava.net/byrtiger/archive/2008/12/03/244078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载：JDK5.0垃圾收集优化之--Don't Pause</title><link>http://www.blogjava.net/byrtiger/archive/2008/12/03/244075.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Wed, 03 Dec 2008 01:51:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/12/03/244075.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/244075.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/12/03/244075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/244075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/244075.html</trackback:ping><description><![CDATA[<p><strong>一、参考资料：</strong> </p>
<ol>
    <li><a href="http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html"><font color="#669966">Tuning Garbage Collection with the 5.0 Java Virtual Machine</font></a>&nbsp;官方指南。
    <li><a href="https://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf"><font color="#669966">Hotspot memory management whitepaper</font></a>&nbsp;官方白皮书。
    <li><a href="http://java.sun.com/performance/reference/whitepapers/tuning.html"><font color="#669966">Java Tuning White Paper</font></a> 官方文档。
    <li><a href="http://java.sun.com/docs/hotspot/gc1.4.2/faq.html"><font color="#669966">FAQ about Garbage Collection in the Hotspot&nbsp;</font></a> 官方FAQ，JVM1.4.2。
    <li><a href="http://gceclub.sun.com.cn/java_one_online/2004/TS-1216CHI(USA,2004)/ts1216ch.pdf"><font color="#669966">Java HotSpot 虚拟机中的垃圾收集</font></a>&nbsp;JavaOne2004上的中文ppt
    <li><a href="http://blogs.sun.com/watt/resource/jvm-options-list.html"><font color="#669966">A Collection of JVM Options</font></a>&nbsp;JVM选项的超完整收集。 </li>
</ol>
<p><strong>二、基本概念</strong> </p>
<p><strong>1、堆(Heap)</strong> </p>
<p>JVM管理的内存叫堆。在32Bit操作系统上有1.5G-2G的限制，而64Bit的就没有。 </p>
<p>JVM初始分配的内存由-Xms指定，默认是物理内存的1/64但小于1G。 </p>
<p>JVM最大分配的内存由-Xmx指定，默认是物理内存的1/4但小于1G。 </p>
<p>默认空余堆内存小于40%时，JVM就会增大堆直到-Xmx的最大限制，可以由-XX:MinHeapFreeRatio=指定。 <br />
默认空余堆内存大于70%时，JVM会减少堆直到-Xms的最小限制，可以由-XX:MaxHeapFreeRatio=指定。 </p>
<p>服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小，所以上面的两个参数没啥用。&nbsp; </p>
<p><strong></strong></p>
<p><strong>2.基本收集算法</strong> </p>
<ol>
    <li><strong>复制</strong>：将堆内分成两个相同空间，从根(ThreadLocal的对象，静态对象）开始访问每一个关联的活跃对象，将空间A的活跃对象全部复制到空间B，然后一次性回收整个空间A。<br />
    因为只访问活跃对象，将所有活动对象复制走之后就清空整个空间，不用去访问死对象，所以遍历空间的成本较小，但需要巨大的复制成本和较多的内存。
    <li><strong>标记清除(mark-sweep)：</strong>收集器先从根开始访问所有活跃对象，标记为活跃对象。然后再遍历一次整个内存区域，把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大，而且整理后堆里的碎片很多。
    <li><strong>标记整理(mark-sweep-compact)：</strong>综合了上述两者的做法和优点，先标记活跃对象，然后将其合并成较大的内存块。 </li>
</ol>
<p>&nbsp;&nbsp;&nbsp; 可见，没有免费的午餐，无论采用复制还是标记清除算法，自动的东西都要付出很大的性能代价。 </p>
<p><strong>3.分代</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 分代是Java垃圾收集的一大亮点，根据对象的生命周期长短，把堆分为3个代：Young，Old和Permanent，根据不同代的特点采用不同的收集算法，扬长避短也。 </p>
<p><strong>Young(Nursery)，年轻代</strong>。研究表明大部分对象都是朝生暮死，随生随灭的。因此所有收集器都为年轻代选择了复制算法。<br />
&nbsp;&nbsp;&nbsp; 复制算法优点是只访问活跃对象，缺点是复制成本高。因为年轻代只有少量的对象能熬到垃圾收集，因此只需少量的复制成本。而且复制收集器只访问活跃对象，对那些占了最大比率的死对象视而不见，充分发挥了它遍历空间成本低的优点。 </p>
<p>&nbsp;&nbsp;&nbsp; Young的默认值为4M，随堆内存增大，约为1/15，JVM会根据情况动态管理其大小变化。<br />
&nbsp;&nbsp;&nbsp; -XX:NewRatio= 参数可以设置Young与Old的大小比例，-server时默认为1:2，但实际上young启动时远低于这个比率？如果信不过JVM，也可以用-Xmn硬性规定其大小，有文档推荐设为Heap总大小的1/4。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;Young的大小非常非常重要，见&#8220;后面暂停时间优先收集器&#8221;的论述。 </p>
<p>&nbsp;&nbsp;&nbsp; Young里面又分为3个区域，一个Eden，所有新建对象都会存在于该区，两个Survivor区，用来实施复制算法。每次复制就是将Eden和第一块Survior的活对象复制到第2块，然后清空Eden与第一块Survior。Eden与Survivor的比例由-XX:SurvivorRatio=设置，默认为32。Survivio大了会浪费，小了的话，会使一些年轻对象潜逃到老人区，引起老人区的不安，但这个参数对性能并不重要。&nbsp; </p>
<p><strong>Old(Tenured)，年老代</strong>。年轻代的对象如果能够挺过数次收集，就会进入老人区。老人区使用标记整理算法。因为老人区的对象都没那么容易死的，采用复制算法就要反复的复制对象，很不合算，只好采用标记清理算法，但标记清理算法其实也不轻松，每次都要遍历区域内所有对象，所以还是没有免费的午餐啊。 </p>
<p>-XX:MaxTenuringThreshold=设置熬过年轻代多少次收集后移入老人区，CMS中默认为0，熬过第一次GC就转入，可以用-XX:+PrintTenuringDistribution查看。 </p>
<p><strong>Permanent，持久代。</strong>装载Class信息等基础数据，默认64M，如果是类很多很多的服务程序，需要加大其设置-XX:MaxPermSize=，否则它满了之后会引起fullgc()或Out of Memory。 注意Spring，Hibernate这类喜欢AOP动态生成类的框架需要更多的持久代内存。 </p>
<p><strong>4.minor/major collection</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 每个代满了之后都会促发collection，（另外Concurrent Low Pause Collector默认在老人区68%的时候促发)。GC用较高的频率对young进行扫描和回收，这种叫做minor collection<strong>。<br />
</strong>而因为成本关系对Old的检查回收频率要低很多，同时对Young和Old的收集称为major collection。<br />
&nbsp;&nbsp;&nbsp; System.gc()会引发major collection，使用-XX:+DisableExplicitGC禁止它，或设为CMS并发-XX:+ExplicitGCInvokesConcurrent。 </p>
<p><strong>5.小结</strong> </p>
<p>Young -- minor collection -- 复制算法 </p>
<p>Old(Tenured) -- major colletion -- 标记清除/标记整理算法 </p>
<p><strong></strong></p>
<p><strong>三、收集器</strong> </p>
<p><strong>1.古老的串行收集器(Serial Collector)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 使用 -XX:+UseSerialGC，策略为年轻代串行复制，年老代串行标记整理。 </p>
<p><strong>2.吞吐量优先的并行收集器(Throughput Collector)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 使用 -XX:+UseParallelGC ，也是JDK5 -server的默认值。策略为：<br />
&nbsp;&nbsp;&nbsp; 1.年轻代暂停应用程序，多个垃圾收集线程并行的复制收集，线程数默认为CPU个数，CPU很多时，可用&#8211;XX:ParallelGCThreads=减少线程数。<br />
&nbsp;&nbsp;&nbsp; 2.年老代暂停应用程序，与串行收集器一样，单垃圾收集线程标记整理。 </p>
<p>&nbsp;&nbsp;&nbsp; 所以需要2+的CPU时才会优于串行收集器，适用于后台处理，科学计算。 </p>
<p>&nbsp;&nbsp;&nbsp; 可以使用-XX:MaxGCPauseMillis= 和 -XX:GCTimeRatio 来调整GC的时间。 </p>
<p><strong>3.暂停时间优先的并发收集器(Concurrent Low Pause Collector-CMS</strong><strong>)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 前面说了这么多，都是为了这节做铺垫...... </p>
<p>&nbsp;&nbsp;&nbsp; 使用-XX:+UseConcMarkSweepGC，策略为：<br />
&nbsp;&nbsp;&nbsp; 1.年轻代同样是暂停应用程序，多个垃圾收集线程并行的复制收集。<br />
&nbsp;&nbsp;&nbsp;&nbsp;2.年老代则只有两次短暂停，其他时间应用程序与收集线程并发的清除。 </p>
<p><strong>3.1 年老代详述</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 并行(Parallel)与并发(Concurrent)仅一字之差，并行指多条垃圾收集线程并行，并发指用户线程与垃圾收集线程并发，程序在继续运行，而垃圾收集程序运行于另一个个CPU上。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;并发收集一开始会很短暂的停止一次所有线程来开始初始标记根对象，然后标记线程与应用线程一起并发运行，最后又很短的暂停一次，多线程<strong>并行</strong>的重新标记之前可能因为并发而漏掉的对象，然后就开始与应用程序并发的清除过程。可见，最长的两个遍历过程都是与应用程序并发执行的，比以前的串行算法改进太多太多了！！！ </p>
<p>&nbsp;&nbsp;&nbsp; 串行标记清除是等年老代满了再开始收集的，而并发收集因为要与应用程序一起运行，如果满了才收集，应用程序就无内存可用，所以系统默认68%满的时候就开始收集。内存已设得较大，吃内存又没有这么快的时候，可以用-XX:CMSInitiatingOccupancyFraction=恰当增大该比率。 </p>
<p><strong>3.2 年轻代详述</strong> </p>
<p>&nbsp;&nbsp;&nbsp;可惜对年轻代的复制收集，依然必须停止所有应用程序线程，原理如此，只能靠多CPU，多收集线程并发来提高收集速度，但除非你的Server独占整台服务器，否则如果服务器上本身还有很多其他线程时，切换起来速度就..... 所以，搞到最后，暂停时间的瓶颈就落在了年轻代的复制算法上。 </p>
<p>&nbsp;&nbsp;&nbsp; 因此Young的大小设置挺重要的，大点就不用频繁GC，而且增大GC的间隔后，可以让多点对象自己死掉而不用复制了。但Young增大时，GC造成的停顿时间攀升得非常恐怖，比如在我的机器上，默认8M的Young，只需要几毫秒的时间，64M就升到90毫秒，而升到256M时，就要到300毫秒了，峰值还会攀到恐怖的800ms。谁叫复制算法，要等Young满了才开始收集，开始收集就要停止所有线程呢。 </p>
<p><strong>3.3 持久代</strong> </p>
<p>可设置-XX:+CMSClassUnloadingEnabled <code>-XX:+CMSPermGenSweepingEnabled，使CMS收集持久代的类，而不是fullgc，netbeans5.5 performance文档的推荐。</code> </p>
<p><strong>4.增量(train算法)收集器(Incremental Collector)</strong> </p>
<p>已停止维护，&#8211;Xincgc选项默认转为并发收集器。 </p>
<p><strong>四、暂停时间显示</strong> </p>
<p>&nbsp;加入下列参数 (请将PrintGC和Details中间的空格去掉，CSDN很怪的认为是禁止字句）&nbsp; </p>
<p><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />-verbose:gc&nbsp;-XX:+PrintGC Details&nbsp;&nbsp;-XX:+PrintGCTimeStamps </p>
<p>会程序运行过程中将显示如下输出 </p>
<p>&nbsp;9.211: [GC 9.211: [ParNew: 7994K-&gt;0K(8128K), 0.0123935 secs] 427172K-&gt;419977K(524224K), 0.0125728 secs] </p>
<p>&nbsp;显示在程序运行的9.211秒发生了Minor的垃圾收集，前一段数据针对新生区，从7994k整理为0k，新生区总大小为8128k，程序暂停了12ms，而后一段数据针对整个堆。 </p>
<p>对于年老代的收集，暂停发生在下面两个阶段，CMS-remark的中断是17毫秒： </p>
<p>[GC [1 CMS-initial-mark: 80168K(196608K)] 81144K(261184K), 0.0059036 secs]&nbsp; </p>
<p>[1 CMS-remark: 80168K(196608K)] 82493K(261184K),0.0168943 secs] </p>
<p>再加两个参数 -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime对暂停时间看得更清晰。 </p>
<p><strong>五、真正不停的BEA JRockit 与Sun RTS2.0</strong> </p>
<p>&nbsp; &nbsp;Bea的<a href="http://edocs.bea.com/jrockit/webdocs/index.html"><font color="#669966">JRockit 5.0 R27</font></a> 的特色之一是动态决定的垃圾收集策略，用户可以决定自己关心的是吞吐量，暂停时间还是确定的暂停时间，再由JVM在运行时动态决定、改变改变垃圾收集策略。<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 它的Deterministic GC的选项是-Xgcprio: deterministic，号称可以把暂停可以控制在10-30毫秒，非常的牛，一句Deterministic道尽了RealTime的真谛。 不过细看一下文档，30ms的测试环境是1 GB heap 和 平均 &nbsp;30% 的活跃对象(也就是300M)活动对象，2&nbsp;个 Xeon 3.6 GHz&nbsp; 4G内存&nbsp;，或者是4 个Xeon 2.0 GHz，8G内存。 </p>
<p>&nbsp; 最可惜JRockt的license很奇怪，虽然平时使用免费，但这个30ms的选项就需要购买整个Weblogic Real Time Server的license。&nbsp;</p>
<p>&nbsp;&nbsp;其他免费选项，有：</p>
<ul>
    <li>-Xgcprio:pausetime -Xpausetarget=210ms&nbsp;<br />
    &nbsp;&nbsp;因为免费，所以最低只能设置到200ms pause target。&nbsp;200ms是Sun认为Real-Time的分界线。
    <li>-Xgc:gencon<br />
    普通的并发做法，效率也不错。 </li>
</ul>
<p>&nbsp;&nbsp;JavaOne2007上有Sun的 <a href="http://java.sun.com/javase/technologies/realtime/index.jsp"><font color="#669966">Java Real-Time System 2.0</font></a> 的介绍，RTS2.0基于JDK1.5，在Real-Time&nbsp; Garbage Collctor上又有改进，但还在beta版状态，只供给OEM，更怪。 </p>
<p><strong>六、JDK 6.0的改进</strong> </p>
<p>因为JDK5.0在Young较大时的表现还是不够让人满意，又继续看JDK6.0的改进，结果稍稍失望，不涉及我最头痛的年轻代复制收集改良。 </p>
<p><strong>1.年老代的标识-清除收集，并行执行标识</strong><br />
&nbsp; JDK5.0只开了一条收集进程与应用线程并发标识，而6.0可以开多条收集线程来做标识，缩短标识老人区所有活动对象的时间。 </p>
<p><strong>2.加大了Young区的默认大小</strong><br />
默认大小从4M加到16M，从堆内存的1/15增加到1/7 </p>
<p><strong>3.System.gc()可以与应用程序并发执行</strong><br />
使用-XX:+ExplicitGCInvokesConcurrent 设置</p>
<p><strong>七、小结</strong> </p>
<p><strong>1. JDK5.0/6.0</strong></p>
<p>对于服务器应用，我们使用Concurrent Low Pause Collector，对年轻代，暂停时多线程并行复制收集；对年老代，收集器与应用程序并行标记--整理收集，以达到尽量短的垃圾收集时间。 </p>
<p>本着没有深刻测试前不要胡乱优化的宗旨，命令行属性只需简单写为： </p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: #e6e6e6; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; word-break: break-all; padding-top: 4px; border-bottom: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">-server&nbsp;-Xms&lt;heapsize&gt;M&nbsp;-Xmx&lt;heapsize&gt;M&nbsp;-XX:</span><span style="color: #000000">+</span><span style="color: #000000">UseConcMarkSweepGC&nbsp;&nbsp;-XX:+PrintGC Details&nbsp;&nbsp;-XX:+PrintGCTimeStamps </span></div>
</div>
<p>然后要根据应用的情况，在测试软件辅助可以下看看有没有JVM的默认值和自动管理做的不够的地方可以调整，如-xmn 设Young的大小，-XX:MaxPermSize设持久代大小等。 </p>
<p><strong>2. JRockit 6.0&nbsp;R27.2</strong></p>
<p>但因为JDK5的测试结果实在不能满意，后来又尝试了JRockit，总体效果要好些。<br />
&nbsp;JRockit的特点是动态垃圾收集器是根据用户关心的特征动态决定收集算法的，参数如下</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: #e6e6e6; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; word-break: break-all; padding-top: 4px; border-bottom: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;-Xms&lt;heapsize&gt;M&nbsp;-Xmx&lt;heapsize&gt;M <span style="color: #000000">-Xgcprio</span><span style="color: #800000">:pausetime</span><span style="color: #000000">&nbsp;-Xpausetarget</span><span style="color: #000000">=</span><span style="color: #000000">200ms -XgcReport -XgcPause -Xverbose:memory</span></div>
</div>
<img src ="http://www.blogjava.net/byrtiger/aggbug/244075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-12-03 09:51 <a href="http://www.blogjava.net/byrtiger/archive/2008/12/03/244075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 垃圾回收 </title><link>http://www.blogjava.net/byrtiger/archive/2008/12/03/244070.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Wed, 03 Dec 2008 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/12/03/244070.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/244070.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/12/03/244070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/244070.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/244070.html</trackback:ping><description><![CDATA[<script type="text/javascript">
              new Draggable("related_topics");
          </script>
<p><font face="Arial" color="#0000ff"><strong>1.垃圾收集算法的核心思想</strong></font></p>
<p><font face="Arial">　　Java语言建立了垃圾收集机制，用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险：因内存垃圾过多而引发的内存耗尽，以及不恰当的内存释放所造成的内存非法引用。</font></p>
<p><font face="Arial">　　垃圾收集算法的核心思想是：对虚拟机可用内存空间，即堆空间中的对象进行识别，如果对象正在被引用，那么称其为存活对象，反之，如果对象不再被引用，则为垃圾对象，可以回收其占据的空间，用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能，因此需要开发人员做比较深入的了解。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>2.触发主GC(Garbage Collector)的条件</strong></font></font></p>
<p><font face="Arial">　　JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:<br />
&nbsp; </font></p>
<p><font face="Arial">　　①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。</font></p>
<p><font face="Arial">　　②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报&#8220;out of memory&#8221;的错误,Java应用将停止。</font></p>
<p><font face="Arial">　　由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>3.减少GC开销的措施</strong></font></font></p>
<p><font face="Arial">　　根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:</font></p>
<p><font face="Arial">　　(1)不要显式调用System.gc()</font></p>
<p><font face="Arial">　　此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。</font></p>
<p><font face="Arial">　　(2)尽量减少临时对象的使用</font></p>
<p><font face="Arial">　　临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。</font></p>
<p><font face="Arial">　　(3)对象不用时最好显式置为Null</font></p>
<p><font face="Arial">　　一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。</font></p>
<p><font face="Arial">　　(4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章JAVA中String与StringBuffer)</font></p>
<p><font face="Arial">　　由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作&#8220;+&#8221;操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。</font></p>
<p><font face="Arial">　　(5)能用基本类型如Int,Long,就不用Integer,Long对象</font></p>
<p><font face="Arial">　　基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。</font></p>
<p><font face="Arial">　　(6)尽量少用静态对象变量</font></p>
<p><font face="Arial">　　静态变量属于全局变量,不会被GC回收,它们会一直占用内存。</font></p>
<p><font face="Arial">　　(7)分散对象创建或删除的时间</font></p>
<p><font face="Arial">　　集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>4.gc与finalize方法</strong></font></font></p>
<p><font face="Arial">　　⑴gc方法请求垃圾回收</font></p>
<p><font face="Arial">　　使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法，都可以请求Java的垃圾回收。需要注意的是，调用System.gc()也仅仅是一个请求。JVM接受这个消息后，并不是立即做垃圾回收，而只是对几个垃圾回收算法做了加权，使垃圾回收操作容易发生，或提早发生，或回收较多而已。</font></p>
<p><font face="Arial">　　⑵finalize方法透视垃圾收集器的运行</font></p>
<p><font face="Arial">　　在JVM垃圾收集器收集一个对象之前 ，一般要求程序调用适当的方法释放资源，但在没有明确释放资源的情况下，Java提供了缺省机制来终止化该对象释放资源，这个方法就是finalize()。它的原型为：</font></p>
<p><font face="Arial">　　protected void finalize() throws Throwable</font></p>
<p><font face="Arial">　　在finalize()方法返回之后，对象消失，垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。</font></p>
<p><font face="Arial">　　因此，当对象即将被销毁时，有时需要做一些善后工作。可以把这些操作写在finalize()方法里。</font></p>
<p><font face="Arial"></font>&nbsp;</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;finalize()&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="comment">//&nbsp;finalization&nbsp;code&nbsp;here&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;</p>
<p>⑶代码示例<br />
</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">class</span><span>&nbsp;Garbage{&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">int</span><span>&nbsp;index;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;count;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;Garbage()&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;count++;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"object&nbsp;"</span><span>+count+</span><span class="string">"&nbsp;construct"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;setID(count);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">void</span><span>&nbsp;setID(</span><span class="keyword">int</span><span>&nbsp;id)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index=id;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;finalize()&nbsp;</span><span class="comment">//重写finalize方法&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"object&nbsp;"</span><span>+index+</span><span class="string">"&nbsp;is&nbsp;reclaimed"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;System.gc();&nbsp;</span><span class="comment">//请求运行垃圾收集器&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p><font face="Arial"><font color="#0000ff"><strong>5.Java 内存泄漏 <br />
</strong></font>　　由于采用了垃圾回收机制，任何不可达对象(对象不再被引用)都可以由垃圾收集线程回收。因此通常说的Java 内存泄漏其实是指无意识的、非故意的对象引用，或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕，却因为编码的错误而意外地保存了对该对象的引用(这个引用的存在并不是编码人员的主观意愿)，从而使得该对象一直无法被垃圾回收器回收掉，这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被&#8220;泄漏了&#8221;。</font></p>
<p><font face="Arial">　　考虑下面的程序,在ObjStack类中,使用push和pop方法来管理堆栈中的对象。两个方法中的索引(index)用于指示堆栈中下一个可用位置。push方法存储对新对象的引用并增加索引值,而pop方法减小索引值并返回堆栈最上面的元素。在main方法中,创建了容量为64的栈,并64次调用push方法向它添加对象,此时index的值为64,随后又32次调用pop方法,则index的值变为32,出栈意味着在堆栈中的空间应该被收集。但事实上,pop方法只是减小了索引值,堆栈仍然保持着对那些对象的引用。故32个无用对象不会被GC回收,造成了内存渗漏。</font></p>
<p><font face="Arial"></font>&nbsp;</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ObjStack&nbsp;{&nbsp; &nbsp;&nbsp;</span></span> </div>
<ol class="dp-j">
    <li class=""><span>　　&nbsp;</span><span class="keyword">private</span><span>&nbsp;Object[]&nbsp;stack;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;index;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;ObjStack(</span><span class="keyword">int</span><span>&nbsp;indexcount)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;stack&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object[indexcount];&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;push(Object&nbsp;obj)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;stack[index]&nbsp;=&nbsp;obj;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index++;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;pop()&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;index--;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">return</span><span>&nbsp;stack[index];&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Pushpop&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;Object&nbsp;tempobj;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li class=""><span class="comment">//new一个ObjStack对象，并调用有参构造函数。分配stack&nbsp;Obj数组的空间大小为64，可以存64个对象，从0开始存储 </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;ObjStack&nbsp;stack1&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ObjStack(</span><span class="number">64</span><span>); &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">while</span><span>&nbsp;(i&nbsp;&lt;&nbsp;</span><span class="number">64</span><span>)&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;tempobj&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object();</span><span class="comment">//循环new&nbsp;Obj对象，把每次循环的对象一一存放在stack&nbsp;Obj数组中。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;stack1.push(tempobj);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;i++;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;System.out.println(</span><span class="string">"第"</span><span>&nbsp;+&nbsp;i&nbsp;+&nbsp;</span><span class="string">"次进栈"</span><span>&nbsp;+&nbsp;</span><span class="string">"\t"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">while</span><span>&nbsp;(i&nbsp;&gt;&nbsp;</span><span class="number">32</span><span>)&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;tempobj&nbsp;=&nbsp;stack1.pop();</span><span class="comment">//这里造成了空间的浪费。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="comment">//正确的pop方法可改成如下所指示,当引用被返回后,堆栈删除对他们的引用,因此垃圾收集器在以后可以回收他们。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="comment">/*&nbsp; </span>&nbsp;
    <li class=""><span><span class="comment">　　&nbsp;*&nbsp;public&nbsp;Object&nbsp;pop()&nbsp;{index&nbsp;-&nbsp;-;Object&nbsp;temp&nbsp;=&nbsp;stack&nbsp;[index];stack&nbsp;[index]=null;return&nbsp;temp;}&nbsp; </span>&nbsp;</span>
    <li class="alt"><span><span class="comment">　　&nbsp;*/</span><span>&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;i--;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"第"</span><span>&nbsp;+&nbsp;(</span><span class="number">64</span><span>&nbsp;-&nbsp;i)&nbsp;+&nbsp;</span><span class="string">"次出栈"</span><span>&nbsp;+&nbsp;</span><span class="string">"\t"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;</p>
<p><font face="Arial" color="#0000ff"><strong>6.如何消除内存泄漏</strong></font></p>
<p><font face="Arial">　　虽然Java虚拟机(JVM)及其垃圾收集器(garbage collector，GC)负责管理大多数的内存任务，Java软件程序中还是有可能出现内存泄漏。实际上，这在大型项目中是一个常见的问题。避免内存泄漏的第一步是要弄清楚它是如何发生的。本文介绍了编写Java代码的一些常见的内存泄漏陷阱，以及编写不泄漏代码的一些最佳实践。一旦发生了内存泄漏，要指出造成泄漏的代码是非常困难的。因此本文还介绍了一种新工具，用来诊断泄漏并指出根本原因。该工具的开销非常小，因此可以使用它来寻找处于生产中的系统的内存泄漏。</font></p>
<p><font face="Arial">　　垃圾收集器的作用</font></p>
<p><font face="Arial">　　虽然垃圾收集器处理了大多数内存管理问题，从而使编程人员的生活变得更轻松了，但是编程人员还是可能犯错而导致出现内存问题。简单地说，GC循环地跟踪所有来自&#8220;根&#8221;对象(堆栈对象、静态对象、JNI句柄指向的对象，诸如此类)的引用，并将所有它所能到达的对象标记为活动的。程序只可以操纵这些对象;其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象，这么做就是安全的。</font></p>
<p><font face="Arial">　　虽然内存管理可以说是自动化的，但是这并不能使编程人员免受思考内存管理问题之苦。例如，分配(以及释放)内存总会有开销，虽然这种开销对编程人员来说是不可见的。创建了太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些(在其他条件相同的情况下)。</font></p>
<p><font face="Arial">　　而且，与本文更为密切相关的是，如果忘记&#8220;释放&#8221;先前分配的内存，就可能造成内存泄漏。如果程序保留对永远不再使用的对象的引用，这些对象将会占用并耗尽内存，这是因为自动化的垃圾收集器无法证明这些对象将不再使用。正如我们先前所说的，如果存在一个对对象的引用，对象就被定义为活动的，因此不能删除。为了确保能回收对象占用的内存，编程人员必须确保该对象不能到达。这通常是通过将对象字段设置为null或者从集合(collection)中移除对象而完成的。但是，注意，当局部变量不再使用时，没有必要将其显式地设置为null。对这些变量的引用将随着方法的退出而自动清除。</font></p>
<p><font face="Arial">　　概括地说，这就是内存托管语言中的内存泄漏产生的主要原因：保留下来却永远不再使用的对象引用。</font></p>
<p><font face="Arial">　　典型泄漏</font></p>
<p><font face="Arial">　　既然我们知道了在Java中确实有可能发生内存泄漏，就让我们来看一些典型的内存泄漏及其原因。</font></p>
<p><font face="Arial">　　全局集合</font></p>
<p><font face="Arial">　　在大的应用程序中有某种全局的数据储存库是很常见的，例如一个JNDI树或一个会话表。在这些情况下，必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。</font></p>
<p><font face="Arial">　　这可能有多种方法，但是最常见的一种是周期性运行的某种清除任务。该任务将验证储存库中的数据，并移除任何不再需要的数据。</font></p>
<p><font face="Arial">　　另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时，该元素就可以从集合中移除了。</font></p>
<p><font face="Arial">　　缓存</font></p>
<p><font face="Arial">　　缓存是一种数据结构，用于快速查找已经执行的操作的结果。因此，如果一个操作执行起来很慢，对于常用的输入数据，就可以将操作的结果缓存，并在下次调用该操作时使用缓存的数据。</font></p>
<p><font face="Arial">　　缓存通常都是以动态方式实现的，其中新的结果是在执行时添加到缓存中的。典型的算法是：</font></p>
<p><font face="Arial">　　检查结果是否在缓存中，如果在，就返回结果。</font></p>
<p><font face="Arial">　　如果结果不在缓存中，就进行计算。</font></p>
<p><font face="Arial">　　将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。</font></p>
<p><font face="Arial">　　该算法的问题(或者说是潜在的内存泄漏)出在最后一步。如果调用该操作时有相当多的不同输入，就将有相当多的结果存储在缓存中。很明显这不是正确的方法。</font></p>
<p><font face="Arial">　　为了预防这种具有潜在破坏性的设计，程序必须确保对于缓存所使用的内存容量有一个上限。因此，更好的算法是：</font></p>
<p><font face="Arial">　　检查结果是否在缓存中，如果在，就返回结果。</font></p>
<p><font face="Arial">　　如果结果不在缓存中，就进行计算。</font></p>
<p><font face="Arial">　　如果缓存所占的空间过大，就移除缓存最久的结果。</font></p>
<p><font face="Arial">　　将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。</font></p>
<p><font face="Arial">　　通过始终移除缓存最久的结果，我们实际上进行了这样的假设：在将来，比起缓存最久的数据，最近输入的数据更有可能用到。这通常是一个不错的假设。</font></p>
<p><font face="Arial">　　新算法将确保缓存的容量处于预定义的内存范围之内。确切的范围可能很难计算，因为缓存中的对象在不断变化，而且它们的引用包罗万象。为缓存设置正确的大小是一项非常复杂的任务，需要将所使用的内存容量与检索数据的速度加以平衡。</font></p>
<p><font face="Arial">　　解决这个问题的另一种方法是使用java.lang.ref.SoftReference类跟踪缓存中的对象。这种方法保证这些引用能够被移除，如果虚拟机的内存用尽而需要更多堆的话。</font></p>
<p><font face="Arial">　　ClassLoader</font></p>
<p><font face="Arial">　　Java ClassLoader结构的使用为内存泄漏提供了许多可乘之机。正是该结构本身的复杂性使ClassLoader在内存泄漏方面存在如此多的问题。ClassLoader的特别之处在于它不仅涉及&#8220;常规&#8221;的对象引用，还涉及元对象引用，比如：字段、方法和类。这意味着只要有对字段、方法、类或ClassLoader的对象的引用，ClassLoader就会驻留在JVM中。因为ClassLoader本身可以关联许多类及其静态字段，所以就有许多内存被泄漏了。</font></p>
<p><font face="Arial">　　确定泄漏的位置</font></p>
<p><font face="Arial">　　通常发生内存泄漏的第一个迹象是：在应用程序中出现了OutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中，此时几乎不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系统不完全相同，因而导致泄漏只出现在生产中。在这种情况下，需要使用一些开销较低的工具来监控和查找内存泄漏。还需要能够无需重启系统或修改代码就可以将这些工具连接到正在运行的系统上。可能最重要的是，当进行分析时，需要能够断开工具而保持系统不受干扰。</font></p>
<p><font face="Arial">　　虽然OutOfMemoryError通常都是内存泄漏的信号，但是也有可能应用程序确实正在使用这么多的内存;对于后者，或者必须增加JVM可用的堆的数量，或者对应用程序进行某种更改，使它使用较少的内存。但是，在许多情况下，OutOfMemoryError都是内存泄漏的信号。一种查明方法是不间断地监控GC的活动，确定内存使用量是否随着时间增加。如果确实如此，就可能发生了内存泄漏。</font></p>
<img src ="http://www.blogjava.net/byrtiger/aggbug/244070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-12-03 09:41 <a href="http://www.blogjava.net/byrtiger/archive/2008/12/03/244070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中equals() hashcode()方法</title><link>http://www.blogjava.net/byrtiger/archive/2008/08/04/219919.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Mon, 04 Aug 2008 06:38:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/08/04/219919.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/219919.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/08/04/219919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/219919.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/219919.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt"><font size="3"><span style="color: red"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000">&nbsp; <span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 10pt">Java<span style="font-family: 宋体">语言中的</span>equals</span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt">的规范：<br />
</span></span></span></span></span></span></span></span></span></span></span></font></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1．</font>&nbsp;</span></span></span></span></span></span></span></span></span></span><font size="3"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-family: 宋体">自反性：对于任何一个非空引用</span>x<span style="font-family: 宋体">，</span>x.equals(x)<span style="font-family: 宋体">应该返回</span>true</span></span></span></span></span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt">；<br />
</span></span></span></span></span></span></span></span></span></span></span></font><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;2．</font>&nbsp;</span></span></span></span></span></span></span></span></span></span><font size="3"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-family: 宋体">对称性：对于任何引用</span>x<span style="font-family: 宋体">和</span>y<span style="font-family: 宋体">，如果</span>x.equals(y)<span style="font-family: 宋体">返回</span>true<span style="font-family: 宋体">，那么</span>y.equals(x)<span style="font-family: 宋体">也应该返回</span>true</span></span></span></span></span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt">。<br />
</span></span></span></span></span></span></span></span></span></span></span></font><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;3．</font>&nbsp;</span></span></span></span></span></span></span></span></span></span><font size="3"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-family: 宋体">传递性：对于任何引用</span>x<span style="font-family: 宋体">、</span>y<span style="font-family: 宋体">和</span>z<span style="font-family: 宋体">，如果</span>x.equals(y)<span style="font-family: 宋体">返回</span>true<span style="font-family: 宋体">，</span>y.equals(z)<span style="font-family: 宋体">返回</span>true<span style="font-family: 宋体">，那么</span>x.equals(z)<span style="font-family: 宋体">也应该返回</span>true</span></span></span></span></span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt">。<br />
</span></span></span></span></span></span></span></span></span></span></span></font><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;4．</font>&nbsp;</span></span></span></span></span></span></span></span></span></span><font size="3"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-family: 宋体">一致性：如果</span>x<span style="font-family: 宋体">和</span>y<span style="font-family: 宋体">引用的对象没有发生变化，那么反复调用</span>x.equals(y)</span></span></span></span></span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt">应该返回同样的结果。<br />
</span></span></span></span></span></span></span></span></span></span></span></font><span style="color: red"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;5．</font>&nbsp;</span></span></span></span></span></span></span></span></span><font size="3"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 8pt"><span><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-family: 宋体">对于任何非空引用</span>x<span style="font-family: 宋体">，</span>x.equals(null)<span style="font-family: 宋体">应该返回</span>false</span></span></span></span></span></span></span></span></span><span style="font-family: 宋体"><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 8pt">。<br />
</span><br />
</span>&nbsp;public boolean equals(Object obj) {<br />
&nbsp;&nbsp;boolean result = false;<br />
&nbsp;&nbsp;if (this == obj)<br />
&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;if (!(obj instanceof Student))<br />
&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;Student objTemp = (Student) obj;<br />
&nbsp;&nbsp;if (this.getId() == objTemp.getId())<br />
&nbsp;&nbsp;&nbsp;result = true;<br />
&nbsp;&nbsp;return result;<br />
&nbsp;}<br />
<br />
Java语言中的hashcode：</span></span></span></span></span></p>
<span style="font-size: 10.5pt; font-family: 宋体">
<p><span style="color: #000000"><span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt">&nbsp;&nbsp;1. 将一个非0常数，例如17，储存于int result变量中。<br />
&nbsp;&nbsp;2. 对对象中的每一个有意义的字段f（更确切地说是被equals()所考虑的每一个字段）进行如下处理：<br />
&nbsp;&nbsp;&nbsp; A. 对这个字段计算出型别为int的hash 码 c：<br />
</span></span></span><span style="font-size: 18pt"><span style="font-size: 8pt"><span style="font-size: 12pt"><span style="color: #ff6600">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i. 如果字段是个boolean，计算(f ? 0 : 1)。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ii. 如果字段是个byte,char,short或int，计算(int)f。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iii. 如果字段是个long，计算(int)(f^(f &gt;&gt;&gt; 32))。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iv. 如果字段是个float，计算Float.floatToIntBits(f)。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v. 如果字段是个double，计算Double.doubleToLongBits(f)，然后将计算结果按步骤2.A.iii处理。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vi. 如果字段是个object reference，而且class 的equals()透过「递归呼叫equals()」的方式来比较这一字段，那么就同样也对该字段递归呼叫hashCode()。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vii. 如果字段是个array，请将每个元素视为独立字段。也就是说对每一个有意义的元素施行上述规则，用以计算出hash 码，然后再依步骤2.B将这些数值组合起来。<br />
</span>&nbsp;&nbsp;&nbsp; B. 将步骤A计算出来的hash码 c按下列公式组合到变量result中：result = 37*result + c;<br />
&nbsp;3. 传回result。<br />
&nbsp;4. 完成hashCode()之后，反躬自省一下：是否相等的实体具有相等的hash 码？如果不是，找出原因并修正问题。</span></span></span></span></span></span></span></font></span></p>
<img src ="http://www.blogjava.net/byrtiger/aggbug/219919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-08-04 14:38 <a href="http://www.blogjava.net/byrtiger/archive/2008/08/04/219919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载：Java标准类库提供的容器总结</title><link>http://www.blogjava.net/byrtiger/archive/2008/07/03/212296.html</link><dc:creator>追风舞者</dc:creator><author>追风舞者</author><pubDate>Thu, 03 Jul 2008 04:11:00 GMT</pubDate><guid>http://www.blogjava.net/byrtiger/archive/2008/07/03/212296.html</guid><wfw:comment>http://www.blogjava.net/byrtiger/comments/212296.html</wfw:comment><comments>http://www.blogjava.net/byrtiger/archive/2008/07/03/212296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/byrtiger/comments/commentRss/212296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/byrtiger/services/trackbacks/212296.html</trackback:ping><description><![CDATA[<div class="postTitle">
<a id="viewpost1_TitleUrl" class="postTitle2" href="../../javafan/archive/2008/07/02/212029.html">Java标准类库提供的容器总结</a>
</div>
<p>在Java中，容器主要包括：数组(Array)、集合(Collection)和映射(Map)三种。<br />
<br />
(1)数组Array：将数字与元素联系起来，其中的元素都具有相同的数据类型，只能通过下标来访问其元素；数组可以是一维的，也可以是多维的；数组一旦
生成，其容量就不能改变。数组是一种复合数据类型，在Java中，除了可以像&#8220;int[]
array;&#8221;来声明和表示一个数组，还可以用Array类来表示一个数组，同样地，JDK类库还提供了Arrays类类操作数组，该类定义了对数组进行
操作的各种方法(赋值、排序、搜索、比较、查找元素等)。<br />
<br />
(2)集合Collection：是一个接口类，包括List、Set、Queue等子接口，其具体的实现类可以用来保存多个元素。这里只讨论常用的子接
口List和Set的常用实现类。常用的List实现类有ArrayList、Vector和LinkedList等，常用的Set实现类有
HashSet、LinkedHashSet和TreeSet等。需要注意的是，List和Set有着很大的不同，主要包括是否允许元素重复和是否维护元
素的次序。<br />
<br />
(3)映射Map：保存相关联的键值对。其具体的实现类可以将键映射到值，根据键得到值，因此，一个映射不能包含重复的键，但是允许有重复的值，每个键最
多只能映射到一个值。 常见的Map实现类有HashMap、Hashtable、LinkedHashMap和TreeMap等。<br />
<br />
为了讨论的方便，下面以Array，List、Set、Map为分类来讨论这几种容器的使用特点。<br />
<br />
(1)Array：<br />
<br />
<span style="background-color: rgb(255, 255, 255);">&nbsp;&nbsp;&nbsp;&nbsp;数组的使用很直接，主要是根据下表
来获取其元素。其特点就是一旦生成，其容量不能改变，并且每个元素之间不允许有&#8220;空隙&#8221;。其使用实例可以参考电子工业出版社&#8220;宝典&#8221;系列之《Java
JDK 实例宝典》(夏先波
编著)，个人感觉这本书写得不错，给出了许多JDK类库的具体使用实例，代码的注释也比较详细，很适合初学者入门学习使用，如果看Java Doc
还是有不明白的地方，也可以参考此书:)<br />
<br />
(2)List：可用来存放多个元素，能够自动扩充容量，能够维护元素的次序，并且允许元素重复。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(2.1)ArrayList类：最常用的List实现类，内部是通过数组实现的，它允许对元素进行快速的随机访问，但是要从ArrayList
的中间位置插入或者删除&nbsp;&nbsp;&nbsp;&nbsp;元素时，需要对数组进行复制、移动，代价比较高，因此，ArrayList适合随机查找和遍历，不适合插入和删除。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(2.2)Vector类：同ArrayList一样，其内部也是通过数组实现的，不同的是，Vector支持线程的同步，能够避免多线程同时写而引起的不一致，但是实现线程的同步需要很高的代价，因此访问Vector比ArrayList慢。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(2.3)LinkedList类：见其名，该类与链表肯定有关系:)该类的内部是通过链表来实现的，很适合数据的动态插入和删除，但是随即访问
和遍历的速度比较慢。此外，该类还提供了List接口中没有定义的方法，专门用于操作表头和表尾元素，可以当作堆栈、队列和双向队列使用。</span><br />
<br />
(3)Set：可用来存放多个元素，但是不允许元素重复(即不保存重复元素)，也不能够维护元素的次序。很直观，联想一下数学中的集合的概念就很好理解了。此外，需要注意的是，加入Set的元素必须定义equals()方法以确保对象的唯一性，如String对象。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(3.1) HashSet类：采用散列函数对元素进行排序，是专门为快速查询而设计的存入HashSet的对象必须定义hashCode()方法。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(3.2)TreeSet类：采用红黑树的数据结构进行排序元素，使用它可以从Set中提取有序的序列。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(3.3) LinkedHashSet类：内部使用散列以加快查询速度，同时使用链表维护元素的插入次序，在使用迭代器遍历时，会按插入次序显示结果。<br />
<br />
<br />
(4)Map：可以用来存放相关联的键值对，根据键得到值。常见的Map实现类有HashMap、Hashtable、LinkedHashMap和TreeMap。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;(4.1)HashMap类：一个最常用的Map，它根据键的hashCode值存储数据，根据键可以直接获取它的值，具有很快的访问速度，但不支持线程同步。HashMap最多允许一条记录的键为null，但是允许多条记录的值为null。<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;(4.2)Hashtable类：与HashMap类似，但是它不允许记录的键或者值为null，支持线程同步，因而Hashtable在写入数据时会很慢。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(4.3)LinkedHashMap类：保存了记录的插入顺序，在用Iterator遍历它时，先得到的记录肯定时先插入的，在遍历的时候比HashMap慢。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;(4.4)TreeMap类：能够把它保存的记录根据键排序，默认为升序排列。当用Iterator遍历它时，得到的记录是排过序的记录。</p>
<img src ="http://www.blogjava.net/byrtiger/aggbug/212296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/byrtiger/" target="_blank">追风舞者</a> 2008-07-03 12:11 <a href="http://www.blogjava.net/byrtiger/archive/2008/07/03/212296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>