﻿<?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>C++博客-chenglong7997-文章分类-Java</title><link>http://www.cppblog.com/chenglong7997/category/18971.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 12 Apr 2012 16:19:42 GMT</lastBuildDate><pubDate>Thu, 12 Apr 2012 16:19:42 GMT</pubDate><ttl>60</ttl><item><title>java 提高性能</title><link>http://www.cppblog.com/chenglong7997/articles/171006.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 20:31:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/171006.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/171006.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/171006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/171006.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/171006.html</trackback:ping><description><![CDATA[<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">最近的机器内存又爆满了，除了新增机器内存外，还应该好好review一下我们的代码，有很多代码编写过于随意化，这些不好的习惯或对程序语言的不了解是应该好好打压打压了。</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">&nbsp;</p><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>1. 尽量在合适的场合使用单例</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">使用单例可以减轻加载的负担，缩短加载的时间，提高加载的效率，但并不是所有地方都适用于单例，简单来说，单例主要适用于以下三个方面：</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">第一，控制资源的使用，通过线程同步来控制资源的并发访问；</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">第二，控制实例的产生，以达到节约资源的目的；</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">第三，控制数据共享，在不建立直接关联的条件下，让多个不相关的进程或线程之间实现通信。<br /><br /><strong>2. 尽量避免随意使用静态变量</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">要知道，当某个对象被定义为stataic变量所引用，那么gc通常是不会回收这个对象所占有的内存，如</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><div style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace; background-color: transparent; width: 684px; margin-left: 9px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; word-break: break-all; word-wrap: break-word; "><div><div style="padding-right: 3px; padding-bottom: 3px; padding-left: 3px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-weight: bold; ">Java代码&nbsp;<embed wmode="transparent" src="http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" width="14" height="15" flashvars="clipboard=public%20class%20A%7B%0Astatic%20B%20b%20%3D%20new%20B()%3B%0A%7D" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></div></div><ol start="1" style="font-size: 1em; line-height: 1.4em; margin-left: 0px; padding-top: 2px; padding-bottom: 2px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #d1d7dc; border-right-color: #d1d7dc; border-bottom-color: #d1d7dc; border-left-color: #d1d7dc; color: #2b91af; "><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: #7f0055; ">public</span>&nbsp;<span style="color: #7f0055; ">class</span>&nbsp;A{&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: #7f0055; ">static</span>&nbsp;B&nbsp;b&nbsp;=&nbsp;<span style="color: #7f0055; ">new</span>&nbsp;B();&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">}&nbsp;&nbsp;</li></ol></div>&nbsp;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">此时静态变量b的生命周期与A类同步，如果A类不会卸载，那么b对象会常驻内存，直到程序终止。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>3. 尽量避免过多过常的创建Java对象</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">尽量避免在经常调用的方法，循环中new对象，由于系统不仅要花费时间来创建对象，而且还要花时间对这些对象进行垃圾回收和处理，在我们可以控制的范围内，最大限度的重用对象，最好能用基本的数据类型或数组来替代对象。</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>4. 尽量使用final修饰符</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">带有final修饰符的类是不可派生的。在Java核心API中，有许多应用final的例子，例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外，如果一个类是final的，则该类所有方法都是final的。Java编译器会寻找机会内联（inline）所有的final方法（这和具体的编译器实现有关）。此举能够使性能平均提高50%。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>5. 尽量使用局部变量</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">调用方法时传递的参数以及在调用中创建的临时变量都保存在栈（Stack）中，速度较快。其他变量，如静态变量、实例变量等，都在堆（Heap）中创建，速度较慢。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>6. 尽量处理好包装类型和基本类型两者的使用场所</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">虽然包装类型和基本类型在使用过程中是可以相互转换，但它们两者所产生的内存区域是完全不同的，基本类型数据产生和处理都在栈中处理，包装类型是对象，是在堆中产生实例。</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">在集合类对象，有对象方面需要的处理适用包装类型，其他的处理提倡使用基本类型。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>7. 慎用synchronized，尽量减小synchronize的方法</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">都知道，实现同步是要很大的系统开销作为代价的，甚至可能造成死锁，所以尽量避免无谓的同步控制。synchronize方法被调用时，直接会把当前对象锁 了，在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小，并且应尽量使用方法同步代替代码块同步。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>8. 尽量使用StringBuilder和StringBuffer进行字符串连接</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">这个就不多讲了。<br /></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>9. 尽量不要使用finalize方法</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">实际上，将资源清理放在finalize方法中完成是非常不好的选择，由于GC的工作量很大，尤其是回收Young代内存时，大都会引起应用程序暂停，所以再选择使用finalize方法进行资源清理，会导致GC负担更大，程序运行效率更差。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>10. 尽量使用基本数据类型代替对象</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">String str = "hello";</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">上面这种方式会创建一个&#8220;hello&#8221;字符串，而且JVM的字符缓存池还会缓存这个字符串；</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">String str = new String("hello");</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">此时程序除创建字符串外，str所引用的String对象底层还包含一个char[]数组，这个char[]数组依次存放了h,e,l,l,o<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>11. 单线程应尽量使用HashMap、ArrayList</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">HashTable、Vector等使用了同步机制，降低了性能。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>12. 尽量合理的创建HashMap</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">当你要创建一个比较大的hashMap时，充分利用另一个构造函数</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">public HashMap(int initialCapacity, float loadFactor)</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事，在默认中initialCapacity只有16，而loadFactor是 0.75，需要多大的容量，你最好能准确的估计你所需要的最佳大小，同样的Hashtable，Vectors也是一样的道理。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>13. 尽量减少对变量的重复计算</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">for(int i=0;i&lt;list.size();i++)</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">应该改为</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">for(int i=0,len=list.size();i&lt;len;i++)</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">并且在循环中应该避免使用复杂的表达式，在循环中，循环条件会被反复计算，如果不使用复杂表达式，而使循环条件值不变的话，程序将会运行的更快。&nbsp;<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>14. 尽量避免不必要的创建</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">A a = new A();</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">if(i==1){list.add(a);}</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">应该改为</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">if(i==1){</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">A a = new A();</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">list.add(a);}<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>15. 尽量在finally块中释放资源</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">程序中使用到的资源应当被释放，以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何，finally块总是会执行的，以确保资源的正确关闭。&nbsp;<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>16. 尽量使用移位来代替'a/b'的操作</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">"/"是一个代价很高的操作，使用移位的操作将会更快和更有效</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a / 4;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a / 8;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">应该改为</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a &gt;&gt; 2;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a &gt;&gt; 3;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">但注意的是使用移位应添加注释，因为移位操作不直观，比较难理解<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>17.尽量使用移位来代替'a*b'的操作</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">同样的，对于'*'操作，使用移位的操作将会更快和更有效</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a * 4;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a * 8;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">应该改为</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a &lt;&lt; 2;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">int num = a &lt;&lt; 3;<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>18. 尽量确定StringBuffer的容量</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">StringBuffer 的构造器会创建一个默认大小（通常是16）的字符数组。在使用中，如果超出这个大小，就会重新分配内存，创建一个更大的数组，并将原先的数组复制过来，再 丢弃旧的数组。在大多数情况下，你可以在创建 StringBuffer的时候指定大小，这样就避免了在容量不够的时候自动增长，以提高性能。&nbsp;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如：StringBuffer&nbsp;<a title="Powered by Text-Enhance" id="_GPLITA_1" href="http://www.iteye.com/magazines/66#" in_rurl="http://www.textsrv.com/click?v=VVM6MTkwODY6MTIxOmJ1ZmZlcjo3ZDRlM2M0YzRhNmQxNWQzMWQ1Nzg4MmMyYmMxOGE3ZDp6LTEwNDctMTQyMTI6d3d3Lml0ZXllLmNvbQ%3D%3D" style="color: #006699; ">buffer</a>&nbsp;= new StringBuffer(1000); &nbsp;<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>19. 尽量早释放无用对象的引用</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">大部分时，方法局部引用变量所引用的对象 会随着方法结束而变成垃圾，因此，大部分时候程序无需将局部，引用变量显式设为null。</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">例如：</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><div style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace; background-color: transparent; width: 684px; margin-left: 9px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; word-break: break-all; word-wrap: break-word; "><div><div style="padding-right: 3px; padding-bottom: 3px; padding-left: 3px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-weight: bold; ">Java代码&nbsp;<embed wmode="transparent" src="http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" width="14" height="15" flashvars="clipboard=Public%20void%20test()%7B%0AObject%20obj%20%3D%20new%20Object()%3B%0A%E2%80%A6%E2%80%A6%0AObj%3Dnull%3B%0A%7D" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></div></div><ol start="1" style="font-size: 1em; line-height: 1.4em; margin-left: 0px; padding-top: 2px; padding-bottom: 2px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #d1d7dc; border-right-color: #d1d7dc; border-bottom-color: #d1d7dc; border-left-color: #d1d7dc; color: #2b91af; "><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Public&nbsp;<span style="color: #7f0055; ">void</span>&nbsp;test(){&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Object&nbsp;obj&nbsp;=&nbsp;<span style="color: #7f0055; ">new</span>&nbsp;Object();&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">&#8230;&#8230;&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Obj=<span style="color: #7f0055; ">null</span>;&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">}&nbsp;&nbsp;</li></ol></div>&nbsp;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">上面这个就没必要了，随着方法test()的执行完成，程序中obj引用变量的作用域就结束了。但是如果是改成下面：</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><div style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace; background-color: transparent; width: 684px; margin-left: 9px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; word-break: break-all; word-wrap: break-word; "><div><div style="padding-right: 3px; padding-bottom: 3px; padding-left: 3px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-weight: bold; ">Java代码&nbsp;<embed wmode="transparent" src="http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" width="14" height="15" flashvars="clipboard=Public%20void%20test()%7B%0AObject%20obj%20%3D%20new%20Object()%3B%0A%E2%80%A6%E2%80%A6%0AObj%3Dnull%3B%0A%2F%2F%E6%89%A7%E8%A1%8C%E8%80%97%E6%97%B6%EF%BC%8C%E8%80%97%E5%86%85%E5%AD%98%E6%93%8D%E4%BD%9C%EF%BC%9B%E6%88%96%E8%B0%83%E7%94%A8%E8%80%97%E6%97%B6%EF%BC%8C%E8%80%97%E5%86%85%E5%AD%98%E7%9A%84%E6%96%B9%E6%B3%95%0A%E2%80%A6%E2%80%A6%0A%7D" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></div></div><ol start="1" style="font-size: 1em; line-height: 1.4em; margin-left: 0px; padding-top: 2px; padding-bottom: 2px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #d1d7dc; border-right-color: #d1d7dc; border-bottom-color: #d1d7dc; border-left-color: #d1d7dc; color: #2b91af; "><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Public&nbsp;<span style="color: #7f0055; ">void</span>&nbsp;test(){&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Object&nbsp;obj&nbsp;=&nbsp;<span style="color: #7f0055; ">new</span>&nbsp;Object();&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">&#8230;&#8230;&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">Obj=<span style="color: #7f0055; "><a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.iteye.com/magazines/66#" in_rurl="http://www.textsrv.com/click?v=VVM6MTg2MTE6MTQzOTpudWxsOmQzMjI1MTRhOTI3MmMyNDEyZDljMGRkNzI1MDRmZWEyOnotMTA0Ny0xNDIxMjp3d3cuaXRleWUuY29t" style="color: #006699; ">null</a></span>;&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">//执行耗时，耗内存操作；或调用耗时，耗内存的方法&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">&#8230;&#8230;&nbsp;&nbsp;</li><li style="font-size: 1em; margin-left: 38px; padding-right: 0px; border-left-width: 1px; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; ">}&nbsp;&nbsp;</li></ol></div>&nbsp;</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">这时候就有必要将obj赋值为null，可以尽早的释放对Object对象的引用。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>20. 尽量避免使用二维数组</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">二维数据占用的内存空间比一维数组多得多，大概10倍以上。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>21. 尽量避免使用split</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">除非是必须的，否则应该避免使用split，split由于支持正则表达式，所以效率比较低，如果是频繁的几十，几百万的调用将会耗费大量资源，如果确实需 要频繁的调用split，可以考虑使用apache的StringUtils.split(string,char)，频繁split的可以缓存结果。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>22. ArrayList &amp; LinkedList</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">一 个是线性表，一个是链表，一句话，随机查询尽量使用ArrayList，ArrayList优于LinkedList，LinkedList还要移动指 针，添加删除的操作LinkedList优于ArrayList，ArrayList还要移动数据，不过这是理论性分析，事实未必如此，重要的是理解好2 者得数据结构，对症下药。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>23. 尽量使用System.arraycopy ()代替通过来循环复制数组</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">System.arraycopy() 要比通过循环来复制数组快的多&nbsp;<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>24. 尽量缓存经常使用的对象</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">尽可能将经常使用的对象进行缓存，可以使用数组，或HashMap的容器来进行缓存，但这种方式可能导致系统占用过多的缓存，性能下降，推荐可以使用一些第三方的开源工具，如EhCache，Oscache进行缓存，他们基本都实现了FIFO/FLU等缓存算法。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>25. 尽量避免非常大的内存分配</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">有时候问题不是由当时的堆状态造成的，而是因为分配失败造成的。分配的内存块都必须是连续的，而随着堆越来越满，找到较大的连续块越来越困难。<br /><div></div></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "><strong>26. 慎用异常</strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; "></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">当创建一个异常时，需要收集一个栈跟踪(stack track)，这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照，正是这一部分开销很大。当需要创建一个 Exception 时，JVM 不得不说：先别动，我想就您现在的样子存一份快照，所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素，而是包含这个栈中的每一个元素。</div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">如 果您创建一个 Exception ，就得付出代价。好在捕获异常开销不大，因此可以使用 try-catch 将核心内容包起来。从技术上讲，您甚至可以随意地抛出异常，而不用花费很大的代价。招致性能损失的并不是 throw 操作&#8212;&#8212;尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是，好的编程习惯已教会我们，不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的，使用时也应该牢记这一原则。</div><img src ="http://www.cppblog.com/chenglong7997/aggbug/171006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-12 04:31 <a href="http://www.cppblog.com/chenglong7997/articles/171006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中clone（）</title><link>http://www.cppblog.com/chenglong7997/articles/170906.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:08:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170906.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170906.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170906.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170906.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170906.html</trackback:ping><description><![CDATA[<pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "> <strong style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">目录</strong>&nbsp;<br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">预备知识&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">为什么要clone&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">Object的clone以及为什么如此实现&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">如何clone&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">对clone的态度&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">其他的选择&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">和Serializable的比较&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">性能&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><strong style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">预备知识</strong>&nbsp;<br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">为了理解java的clone，有必要先温习以下的知识。&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">java的类型，java的类型分为两大类，一类为primitive，如int，另一类为引用类型,如String,Object等等。&nbsp;</span><br style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; " /><span style="font-family: Tahoma; text-align: -webkit-left; white-space: normal; ">java引用类型的存储，java的引用类型都是存储在堆上的</span> <br />public class B { 	int a; 	String b; 	public B(int a, String b) { 		super(); 		this.a = a; 		this.b = b; 	} }</pre><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对这样一个引用类型的实例，我们可以推测，在堆上它的内存存储形式（除去指向class的引用，锁的管理等等内务事务所占内存），应该有一个int值表示a,以及一个引用，该引用指向b在堆上的存储空间。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><img src="http://www.java3z.com/cwbwebhome/article/article8/img4/ab566d78-88a1-3af6-8f32-2d9091f1178a.jpg" style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "  alt="" />&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">为什么要clone</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">恩，因为需要。废话。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">有名的GoF设计模式里有一个模式为原型模式，用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">简单的说就是clone一个对象实例。使得clone出来的copy和原有的对象一模一样。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">插一个简单使用clone的例子，如果一个对象内部有可变对象实例的话，public API不应该直接返回该对象的引用，以防调用方的code改变该对象的内部状态。这个时候可以返回该对象的clone。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">问题来了，什么叫一模一样。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">一般来说，有&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">x.clone() != x&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">x.clone().getClass() == x.getClass()&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">x.clone().equals(x)&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">但是这些都不是强制的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">我们需要什么样的clone就搞出什么样的clone好了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">一般而言，我们要的clone应该是这样的。copy和原型的内容一样，但是又是彼此隔离的。即在clone之后，改变其中一个不影响另外一个。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Object的clone以及为什么如此实现</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Object的clone的行为是最简单的。以堆上的内存存储解释的话（不计内务内存），对一个对象a的clone就是在堆上分配一个和a在堆上所占存储空间一样大的一块地方，然后把a的堆上内存的内容复制到这个新分配的内存空间上。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">看例子。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">class User { 	String name; 	int age; } class <a title="Powered by Text-Enhance" id="_GPLITA_1" href="http://www.java3z.com/cwbwebhome/article/article8/81145.html?id=2600#" in_rurl="http://www.textsrv.com/click?v=VVM6MTc5MDM6MzM2OmFjY291bnQ6ZTM2MDAwMzc1MzQ1NjdjYTBmYjc2Y2U2MDc0MmFjNjA6ei0xMDQ3LTE0MjEyOnd3dy5qYXZhM3ouY29t" style="font-family: Tahoma; color: #0066ff; ">Account</a> implements Cloneable { 	User user; 	long balance; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }</pre><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// account. 		Account account = <a title="Powered by Text-Enhance" id="_GPLITA_2" href="http://www.java3z.com/cwbwebhome/article/article8/81145.html?id=2600#" in_rurl="http://www.textsrv.com/click?v=VVM6MTQzNTM6NjgwOm5ldyBhY2NvdW50OmE0ODdiZmVhZmY5YjUxMGM4NjQ1MTU0MWEyNTgxNmU1OnotMTA0Ny0xNDIxMjp3d3cuamF2YTN6LmNvbQ%3D%3D" style="font-family: Tahoma; color: #0066ff; ">new Account</a>(); 		account.user = user; 		account.balance = 10000; 		// copy. 		Account copy = (Account) account.clone(); 		// balance因为是primitive，所以copy和原型是相等且独立的。 		Assert.assertEquals(copy.balance, account.balance); 		copy.balance = 20000; 		// 改变copy不影响原型。 		Assert.assertTrue(copy.balance != account.balance); 		// user因为是引用类型，所以copy和原型的引用是同一的。 		Assert.assertTrue(copy.user == account.user); 		copy.user.name = "newName"; 		// 改变的是同一个东西。 		Assert.assertEquals("newName", account.user.name);</pre><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><img src="http://www.java3z.com/cwbwebhome/article/article8/img4/6789f11f-e442-3216-86ee-08a40049fe21.jpg" style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "  alt="" />&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">恩，默认实现是帮了我们一些忙，但是不是全部。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">primitive的确做到了相等且隔离。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">引用类型仅仅是复制了一下引用，copy和原型引用的东西是一样的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">这个就是所谓的浅copy了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">要实现深copy，即复制原型中对象的内存copy，而不仅仅是一个引用。只有自己动手了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">等等，是不是所有的引用类型都需要深copy呢？&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">不是！&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">我们之所以要深copy，是因为默认的实现提供的浅copy不是隔离的，换言之，改变copy的东西，会影响到原型的内部。比如例子中，改变copy的user的name，影响了原型。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如果我们要copy的类是不可变的呢，如String，没有方法可以改变它的内部状态呢。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">class User implements Cloneable { 	String name; 	int age; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }</pre><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// copy 		User copy = (User) user.clone(); 		// age因为是primitive，所以copy和原型是相等且独立的。 		Assert.assertEquals(copy.age, user.age); 		copy.age = 30; 		// 改变copy不影响原型。 		Assert.assertTrue(copy.age != user.age); 		// name因为是引用类型，所以copy和原型的引用是同一的。 		Assert.assertTrue(copy.name == user.name); 		// String为不可变类。没有办法可以通过对copy.name的字符串的操作改变这个字符串。 		// 改变引用新的对象不会影响原型。 		copy.name = "newname"; 		Assert.assertEquals("newname", copy.name); 		Assert.assertEquals("user", user.name);</pre><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">可见，</span><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">在考虑clone时，primitive和不可变对象类型是可以同等对待的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">java为什么如此实现clone呢？&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">也许有以下考虑。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1 效率和简单性，简单的copy一个对象在堆上的的内存比遍历一个对象网然后内存深copy明显效率高并且简单。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2 不给别的类强加意义。如果A实现了Cloneable，同时有一个引用指向B，如果直接复制内存进行深copy的话，意味着B在意义上也是支持Clone的，但是这个是在使用B的A中做的，B甚至都不知道。破坏了B原有的接口。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3 有可能破坏语义。如果A实现了Cloneable，同时有一个引用指向B，该B实现为单例模式，如果直接复制内存进行深copy的话，破坏了B的单例模式。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">4 方便且更灵活，如果A引用一个不可变对象，则内存deep copy是一种浪费。Shadow copy给了程序员更好的灵活性。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如何clone</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">clone三部曲。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1 声明实现Cloneable接口。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2 调用super.clone拿到一个对象，如果父类的clone实现没有问题的话，在该对象的内存存储中，所有父类定义的field都已经clone好了，该类中的primitive和不可变类型引用也克隆好了，可变类型引用都是浅copy。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3 把浅copy的引用指向原型对象新的克隆体。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">给个例子。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre name="code" style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">class User implements Cloneable { 	String name; 	int age; 	@Override 	public User clone() throws CloneNotSupportedException { 		return (User) super.clone(); 	} } class Account implements Cloneable { 	User user; 	long balance; 	@Override 	public Account clone() throws CloneNotSupportedException { 		Account account = <a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81145.html?id=2600#" in_rurl="http://www.textsrv.com/click?v=VVM6MTg4NDU6MTQzOTpudWxsOmUwZTFhNGI4NDhiYzI2MzU2OTNhMzRlYzQ5MDI4MmJjOnotMTA0Ny0xNDIxMjp3d3cuamF2YTN6LmNvbQ%3D%3D" style="font-family: Tahoma; color: #0066ff; ">null</a>; 		account = (Account) super.clone(); 		if (user != null) { 			account.user = user.clone(); 		} 		return account; 	} }</pre><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><img src="http://www.java3z.com/cwbwebhome/article/article8/img4/56fde0bd-4219-3b22-9f94-ae51d55e4e2d.jpg" style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "  alt="" />&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对clone的态度</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">clone嘛，我觉得是个好东西，毕竟系统默认实现已经帮我们做了很多事情了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">但是它也是有缺点的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1 手工维护clone的调用链。这个问题不大，程序员有责任做好。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2 如果class的field是个final的可变类，就不行了。三部曲的第三步没有办法做了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">考虑一个类对clone的态度，有如下几种。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1 公开支持：好吧，按照clone三部曲实现吧。前提是父类支持（公开或者默默）。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2 默默支持：不实现Cloneable接口，但是在类里面有正确的protected的clone实现，这样，该类不支持clone，但是它的子类如果想支持的话也不妨碍。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3 不支持：好吧，为了明确该目的，提供一个抛CloneNotSupportedException 异常的protected的clone实现。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">4 看情况支持：该类内部可以保存其他类的实例，如果其他类支持则该类支持，如果其他类不支持，该类没有办法，只有不支持。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其他的选择</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">可以用原型构造函数，或者静态copy方法来手工制作一个对象的copy。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">好处是即使class的field为final，也不会影响该方法的使用。不好的地方是所有的primitive赋值都得自己维护。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">和Serializable的比较</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">使用Serializable同样可以做到对象的clone。但是：&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Cloneable本身就是为clone设计的，虽然有一些缺点，但是如果它可以clone的话无疑用它来做clone比较合适。如果不行的话用原型构造函数，或者静态copy方法也可以。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Serializable制作clone的话，添加了太多其它的东西，增加了复杂性。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1 所有的相关的类都得支持Serializable。这个相比支持Cloneable只会工作量更大&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2 Serializable添加了更多的意义，除了提供一个方法用Serializable制作Clone，该类等于也添加了其它的public API，如果一个类实现了Serializable，等于它的2进制形式就已经是其API的一部分了，不便于该类以后内部的改动。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3 当类用Serializable来实现clone时，用户如果保存了一个老版本的对象2进制，该类升级，用户用新版本的类反系列化该对象，再调用该对象用Serializable实现的clone。这里为了一个clone的方法又引入了类版本兼容性的问题。不划算。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><strong style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">性能</strong>&nbsp;<br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">不可否认，JVM越来越快了。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">但是系统默认的native实现还是挺快的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">clone一个有100个元素的int数组，用系统默认的clone比静态copy方法快2倍左右。</span>&nbsp;<img src ="http://www.cppblog.com/chenglong7997/aggbug/170906.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:08 <a href="http://www.cppblog.com/chenglong7997/articles/170906.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java instance（）</title><link>http://www.cppblog.com/chenglong7997/articles/170905.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170905.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170905.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170905.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170905.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出，这个对象是否是这个特定类或者是它的子类的一个实例。<br />&nbsp;用法：<br />result = object instanceof class<br />参数：<br />Result：布尔类型。<br />Object：必选项。任意对象表达式。<br />Class：必选项。任意已定义的对象类。<br />说明：<br />如果 object 是 class 的一个实例，则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例，或者 object 是 null，则返回 false。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">例子如下：</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><br />package com.instanceoftest;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;interface A{}<br />&nbsp;class B implements A{<br />&nbsp;&nbsp;<br />&nbsp;}<br />&nbsp;class C extends B {<br />&nbsp;&nbsp;<br />&nbsp;}<br />&nbsp;<br />&nbsp;class instanceoftest {<br />&nbsp; public static void main(String[] args){<br />&nbsp;&nbsp;&nbsp;&nbsp; A a=null;<br />&nbsp;&nbsp;&nbsp;&nbsp; B b=null;<br />&nbsp;&nbsp;&nbsp;&nbsp; boolean res;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("instanceoftest test case 1: ------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = a instanceof A;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("a instanceof A: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = b instanceof B;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b instanceof B: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("\ninstanceoftest test case 2: ------------------");&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; a=new B();<br />&nbsp;&nbsp;&nbsp;&nbsp; b=new B();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = a instanceof A;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("a instanceof A: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = a instanceof B;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("a instanceof B: " + res);</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp; res = b instanceof A;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b instanceof A: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = b instanceof B;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b instanceof B: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("\ninstanceoftest test&nbsp;<a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81199.html?id=2719#" in_rurl="http://www.textsrv.com/click?v=VVM6MTc4MDA6MTMxMjpjYXNlOjYxNzkwNmQzMzAxZTkxNDdhZWM3MDViNmM5ZmVhZTQwOnotMTA0Ny0xNDIxMjp3d3cuamF2YTN6LmNvbQ%3D%3D" style="color: #0066ff; ">case</a>&nbsp;3: ------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp; B b2=(C)new C();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = b2 instanceof A;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b2 instanceof A: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = b2 instanceof B;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b2 instanceof B: " + res);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; res = b2 instanceof C;<br />&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("b2 instanceof C: " + res);<br />&nbsp; }<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><br />/*<br />result:</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><br />instanceoftest test case 1: ------------------<br />a instanceof A: false<br />b instanceof B: false</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">instanceoftest test case 2: ------------------<br />a instanceof A: true<br />a instanceof B: true<br />b instanceof A: true<br />b instanceof B: true</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">instanceoftest test case 3: ------------------<br />b2 instanceof A: true<br />b2 instanceof B: true<br />b2 instanceof C: true</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:07 <a href="http://www.cppblog.com/chenglong7997/articles/170905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析JAVA之垃圾回收机制</title><link>http://www.cppblog.com/chenglong7997/articles/170904.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:06:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170904.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170904.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170904.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170904.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; 对于JAVA编程和很多类似C、C++语言有一个巨大区别就是内存不需要自己去free或者delete，而是由JVM垃圾回收机制去完成的。对于这个过程很多人一直比较茫然或者觉得很智能，使得在写程序的过程不太考虑它的感受，其实知道一些内在的原理，帮助我们编写更加优秀的代码是非常有必要的。本文从以下几个方面进行阐述：1、finalize()方法2、System.gc()方法及一些实用方法3、...&nbsp;&nbsp;<a href='http://www.cppblog.com/chenglong7997/articles/170904.html'>阅读全文</a><img src ="http://www.cppblog.com/chenglong7997/aggbug/170904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:06 <a href="http://www.cppblog.com/chenglong7997/articles/170904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序最容易犯的21种错误</title><link>http://www.cppblog.com/chenglong7997/articles/170903.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:05:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170903.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170903.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170903.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170903.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp; &nbsp;1.Duplicated&nbsp;<a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81349.html?id=3519#" in_rurl="http://www.textsrv.com/click?v=VVM6MTc5MDM6MzM2OmNvZGU6MmNiNDRlYmZmYmExZTcxODk1YTkwYjYyZDY2ZmYyYjY6ei0xMDQ3LTE0MjEyOnd3dy5qYXZhM3ouY29t" style="color: #0066ff; ">Code</a></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　代码重复几乎是最常见的异味了。他也是Refactoring的主要目标之一。代码重复往往来自于copy-and-paste的编程风格。与他相对应OAOO是一个好系统的重要标志。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　2.Long method</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　它是传统结构化的&#8220;遗毒&#8221;。一个方法应当具有自我独立的意图，不要把几个意图放在一起。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　3.Large Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　大类就是你把太多的责任交给了一个类。这里的规则是One Class One Responsibility.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　4.Divergent Change</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　一个类里面的内容变化率不同。某些状态一个小时变一次，某些则几个月一年才变一次；某些状态因为这方面的原因发生变化，而另一些则因为其他方面的原因变一次。面向对象的抽象就是把相对不变的和相对变化相隔离。把问题变化的一方面和另一方面相隔离。这使得这些相对不变的可以重用。问题变化的每个方面都可以单独重用。这种相异变化的共存使得重用非常困难。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　5.Shotgun Surgery</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　这正好和上面相反。对系统一个地方的改变涉及到其他许多地方的相关改变。这些变化率和变化内容相似的状态和行为通常应当放在同一个类中。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　6.Feature Envy</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　对象的目的就是封装状态以及与这些状态紧密相关的行为。如果一个类的方法频繁用get 方法存取其他类的状态进行计算，那么你要考虑把行为移到涉及状态数目最多的那个类。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　7.Data Clumps</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　某些数据通常像孩子一样成群玩耍：一起出现在很多类的成员变量中，一起出现在许多方法的参数中，这些数据或许应该自己独立形成对象。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　8.Primitive Obsession</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　面向对象的新手通常习惯使用几个原始类型的数据来表示一个概念。譬如对于范围，他们会使用两个数字。对于Money，他们会用一个浮点数来表示。因为你没有使用对象来表达问题中存在的概念，这使得代码变的难以理解，解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型，用小对象来表示范围、金额、转化率、邮政编码等等。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　9.Switch Statement</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　基于常量的开关语句是OO 的大敌，你应当把他变为子类、state或strategy.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　10. Parallel Inheritance Hierarchies</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　并行的继承层次是shotgun surgery的特殊情况。因为当你改变一个层次中的某一个类时，你必须同时改变另外一个层次的并行子类。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　11. Lazy Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　一个干活不多的类。类的维护需要额外的开销，如果一个类承担了太少的责任，应当消除它。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　12. Speculative Generality</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　一个类实现了从未用到的功能和通用性。通常这样的类或方法唯一的用户是testcase.不要犹豫，删除它。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　13. Temporary Field</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　一个对象的属性可能只在某些情况下才有意义。这样的代码将难以理解。专门建立一个对象来持有这样的孤儿属性，把只和他相关的行为移到该类。最常见的是一个特定的算法需要某些只有该算法才有用的变量。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　14. Message Chain</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　消息链发生于当一个客户向一个对象要求另一个对象，然后客户又向这另一对象要求另一个对象，再向这另一个对象要求另一个对象，如此如此。这时，你需要隐藏分派。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　15. Middle Man</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　对象的基本特性之一就是封装，而你经常会通过分派去实现封装。但是这一步不能走得太远，如果你发现一个类接口的一大半方法都在做分派，你可能需要移去这个中间人。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　16. Inappropriate Intimacy</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　某些类相互之间太亲密，它们花费了太多的时间去砖研别人的私有部分。对人类而言，我们也许不应该太假正经，但我们应当让自己的类严格遵守禁欲主义。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　17. Alternative Classes with Different Interfaces</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　做相同事情的方法有不同的函数signature，一致把它们往类层次上移，直至协议一致。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　18. Incomplete Library Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而，如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行Refactoring.</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　19. Data Class</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　对象包括状态和行为。如果一个类只有状态没有行为，那么肯定有什么地方出问题了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　20. Refused Bequest</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　超类传下来很多行为和状态，而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　21. Comments</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">　　经常觉得要写很多注释表示你的代码难以理解。如果这种感觉太多，表示你需要Refactoring.</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:05 <a href="http://www.cppblog.com/chenglong7997/articles/170903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java启动方式</title><link>http://www.cppblog.com/chenglong7997/articles/170902.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170902.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170902.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170902.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170902.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170902.html</trackback:ping><description><![CDATA[<ol style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><li>使用&nbsp;<code>-classpath</code>&nbsp;选项:<br /><pre><code>java -classpath C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>-cp</code>&nbsp;选项,&nbsp;&nbsp;<code>-classpath</code>&nbsp;的简写:<br /><pre><code>java -cp C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>-Djava.class.path</code>&nbsp;设置系统属性:<br /><pre><code>java -Djava.class.path=C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>CLASSPATH</code>&nbsp;设置环境变量:<br /><pre><code>set CLASSPATH=C:\hello\build\classes;<br /> java test.HelloWorld<br /></code></pre></li><li>使用当前目录为启动目录:<br /><pre><code>cd C:\hello\build\classes;<br /> java test.HelloWorld</code></pre></li><li>打包所有类进入一个jar包中，并设置对应的<code>&nbsp;META-INF/MANIFEST.MF</code>&nbsp;文件<br /><code>文件内容：<span style="color: #ff0000; ">Main-Class: test.HelloWorld</span>&nbsp;</code><br /><pre><code>java -jar hello-world.jar</code></pre>注意：当使用-jar选项时，-classpath -cp这两个选项将被忽略！</li><li><span style="color: #ff0000; ">写Bash文件进行加载</span></li><li><span style="color: #ff0000; ">如果你使用的是JDK6，加载类路径还支持*通配符加载所有jar文件：java -cp ./lib/* test.HelloWorld</span></li></ol><img src ="http://www.cppblog.com/chenglong7997/aggbug/170902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:01 <a href="http://www.cppblog.com/chenglong7997/articles/170902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java启动方式</title><link>http://www.cppblog.com/chenglong7997/articles/170901.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170901.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170901.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170901.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170901.html</trackback:ping><description><![CDATA[<ol style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><li>使用&nbsp;<code>-classpath</code>&nbsp;选项:<br /><pre><code>java -classpath C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>-cp</code>&nbsp;选项,&nbsp;&nbsp;<code>-classpath</code>&nbsp;的简写:<br /><pre><code>java -cp C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>-Djava.class.path</code>&nbsp;设置系统属性:<br /><pre><code>java -Djava.class.path=C:\hello\build\classes test.HelloWorld<br /></code></pre></li><li>使用&nbsp;<code>CLASSPATH</code>&nbsp;设置环境变量:<br /><pre><code>set CLASSPATH=C:\hello\build\classes;<br /> java test.HelloWorld<br /></code></pre></li><li>使用当前目录为启动目录:<br /><pre><code>cd C:\hello\build\classes;<br /> java test.HelloWorld</code></pre></li><li>打包所有类进入一个jar包中，并设置对应的<code>&nbsp;META-INF/MANIFEST.MF</code>&nbsp;文件<br /><code>文件内容：<span style="color: #ff0000; ">Main-Class: test.HelloWorld</span>&nbsp;</code><br /><pre><code>java -jar hello-world.jar</code></pre>注意：当使用-jar选项时，-classpath -cp这两个选项将被忽略！</li><li><span style="color: #ff0000; ">写Bash文件进行加载</span></li><li><span style="color: #ff0000; ">如果你使用的是JDK6，加载类路径还支持*通配符加载所有jar文件：java -cp ./lib/* test.HelloWorld</span></li></ol><img src ="http://www.cppblog.com/chenglong7997/aggbug/170901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:01 <a href="http://www.cppblog.com/chenglong7997/articles/170901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java重载重写陷阱（2）</title><link>http://www.cppblog.com/chenglong7997/articles/170900.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 06:00:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170900.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170900.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170900.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170900.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>隐藏（hide）：</strong>子类的某个字段、静态方法、成员内部类与其父类的具有相同名字（对于静态方法还需要相同的参数列表），此时父类对应的字段、静态方法、成员内部类就被隐藏了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">举个例子，天鹅（Swan）是会飞的，而丑小鸭（UglyDuck）小时候是不会飞的，看看下面的代码，看看能够打印出什么。</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>class&nbsp;Swan&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;fly()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("swan&nbsp;can&nbsp;fly&nbsp;..."); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>} &nbsp;</li><li>&nbsp;</li><li>class&nbsp;UglyDuck&nbsp;extends&nbsp;Swan&nbsp;{&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;<a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81379.html?id=3838#" in_rurl="http://www.textsrv.com/click?v=VVM6MTg3NzM6MzM2OmZseTozMjE3Yzc1Mjc3MzgxY2IxMDRhYTkyZjZjMjNlNGQwZTp6LTEwNDctMTQyMTI6d3d3LmphdmEzei5jb20%3D" style="font-family: Tahoma; color: #0066ff; ">fly</a>()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("ugly&nbsp;duck&nbsp;can't&nbsp;fly&nbsp;..."); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>} &nbsp;</li><li>&nbsp;</li><li>public&nbsp;class&nbsp;TestFly&nbsp;{&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;[]&nbsp;args)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swan&nbsp;swan&nbsp;=&nbsp;new&nbsp;Swan(); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff00; ">Swan&nbsp;</span>uglyDuck&nbsp;=&nbsp;new&nbsp;UglyDuck(); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;swan.fly(); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uglyDuck.fly(); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>}&nbsp;</li></ol>                       </pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">按道理的话，我们认为应该是输出两句不同的结果，因为我们可能认为 UglyDuck 继承了 Swan 并且&#8220;重写&#8221;了 fly() 方法，而且在 main() 方法中 Swan uglyDuck =&nbsp;<span style="color: #0000ff; ">new</span>&nbsp;UglyDuck();&nbsp; 也表明了 uglyduck 实际上是 UglyDuck 类型的，因此构成了多态行为。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其实，运行结果是两句&#8220;swan can fly ...&#8221;，为什么会这样子？原因有下：</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、父类 Swan 中的 static 静态方法 fly() 是不能被重写的，上一段我对重写二字用了双引号；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、尽管子类 UglyDuck 中的 fly() 方法与父类中的有一致的参数列表，但是对于 static 方法来说，这叫隐藏（hide），而不是重写（override）；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3、对于 static 方法，根本不存在像多态那样的动态分派机制，JVM 不会根据对象引用的实际类型来调用对应的重写方法。这一点在个例子中是最重要的。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对于 static 方法，我们称之为<strong>类方法</strong>，不是<strong>实例方法</strong>，对 static 方法的调用直接用所属类名加个点就行，如 UglyDuck.fly() 。而实例方法就不得不使用对象引用来获得其可访问方法的调用权。在上面的例子 main() 中的 uglyDuck.fly() 语句，JVM 根本据不会去判断 uglyDuck 引用的究竟是什么类型，既然调用的是 fly() 方法，那么 JVM 只会根据 uglyDuck 的声明类型（即 Swan 类）去获得该 static 方法的调用。根本就谈不上多态&#8230;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">这就说明，<strong>最好避免用对象引用的方式来访问一个 static 方法</strong>。此外，<strong>别以为在继承关系上的父类、子类只要方法名、参数列表一致就是重写（override）而构成多态，其实还得看看父类中的方法有没有被什么修饰符声明</strong>（在这个例子中是 static 修饰的）。再如 final 修饰符的方法则表明不可被子类重写，即方法名、参数列表不能和父类完全一致。在我看来，这一类修饰符就表明了方法、变量、字段等特有的性质，或者是身份。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对于隐藏（hide），实际上是为了使得父类中的该方法、字段、内部类等不允许再被下一级继承树的子子类所继承。说起隐藏，我想起《代码大全 2》当中刚好看过的内容，作者认为把握住信息隐藏的原则来思考软件构建要优于面向对象原则。有点抽象难懂，书中还讲到封装、模块化和抽象等几个概念，建议看看，我也要回过头去多啃啃这些抽象概念。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">要修改上面代码，只需要去掉两个 static 则可，那就构成多态了。《Java 解惑》中其他谜题还讲到多种该注意的地方，可以看看。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>小结：</strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、注意掌握重写（override）与隐藏（hide）的异同点：相同点就是两者都是相对于继承树中父类、子类来说，而不同点就是其目的以及所造成的效果。别把重写和隐藏混淆在一起了；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、对于 static 方法，要避免用具体的对象引用来调用，而应该简单的用其所属类名进行调用即可。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;<strong>遮蔽（shadow）：</strong>其实就是平时我们可能遇到的窄作用域的变量名、方法名、类名等将其他相同名字的变量、方法、类屏蔽掉的现象。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">例如，最常见的就是局部变量将类实例变量屏蔽了。其实，遮蔽这个词我之前好像也没什么印象，不过作用域屏蔽这种情况我们大多应该会避免的了，因为课堂上、教材上对于变量作用域的内容已经讲解过了，尽管没有这么一个术语。此时如果想要获得被遮蔽实体的引用、调用，则只能通过完整的限定名去实现了。不过有一些情况可能是根本就引用不到的，被屏蔽得太严密了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;<strong>遮掩（obscure）：</strong>一个变量可以遮掩具有相同名字的一个类，只要它们都在同一个范围内：如果这个名字被用于变量与类型都被许可的范围，那么它将引用到变量上。相似地，一个变量名或一个类名可以遮掩一个包。遮掩是唯一一种两个名字位于不同的名字空间的名字重用形式，这些名字空间包括：变量、包、方法或类。如果一个类型或一个包被遮掩了，那么你不能通过其简单名引用到它，除非是在这样一个上下文环境中，即语法只允许在其名字空间中出现一种名字。遵守命名习惯就可以极大地消除产生遮掩的可能性。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其实，遮掩这个术语我更是完全没听过了，上面这一段是从《Java 解惑》中引用过来的。我觉得，如果代码是一个人所写，或者团队中大家都遵守了一定的命名规范，而且也各自分配了一定职责，那么遮掩这种情况应该是可以避免的。同样，需要使用完全限定名来引用被遮掩掉的实体，如下：</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">用前面例子的代码大概就是这种情况：<br /></p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>public&nbsp;class&nbsp;TestFly&nbsp;{&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如此变量名 &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;String&nbsp;<span style="background-color: #ffff00; ">System&nbsp;</span>=&nbsp;"system"; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;[]&nbsp;args)&nbsp;{ &nbsp;</li><li>&nbsp;</li><li>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;System&nbsp;=&nbsp;"hao";&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;编译不通过 &nbsp;</li><li>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff00; ">System.out.println("No"); </span>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;编译通过 &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.System.out.println("OK"); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>}</li></ol></pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>小结：</strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、我觉得，在文章标题当中的五个名词当中，尤为前面三个最为重要，陷阱炸弹也多多，而且文中所讲仅仅是那么一丁点儿相关的，大量更细节的还得慢慢发现；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、就算后面两个名词，也就是这两种情况不常见，但了解一下记在脑里还是不错的，毕竟为自己增加了专业词汇量；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3、最后，就是建议各位也看看《Java 解惑》然后也告诉我一些炸弹型陷阱之类的，呵呵...学习快乐！加油！</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">本文出自 &#8220;蚂蚁&#8221; 博客，请务必保留此出处http://haolloyin.blog.51cto.com/1177454/372911</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 14:00 <a href="http://www.cppblog.com/chenglong7997/articles/170900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java重载重写陷阱</title><link>http://www.cppblog.com/chenglong7997/articles/170899.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:59:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170899.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170899.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170899.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp; 看《重构（注释版）》中&#8220;封装集合（Encapsulate Collection）&#8221;一节时，由于该重构手法对于不同的 Java 版本会有相对应不同的处理方式，于是注释者在旁边给出提示：Java 2 中的新 Collections API 主要是由《Java 解惑》、《Effective Java》这两本书的作者开发改进的。我想，这可真是一个大消息，Java 类库的开发者所写的书一定得看，开发者肯定深入探寻过 Java 内部机制，说不定能从书中获得未知的知识点呢。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">好在我记得自己电脑里下载过《Java 解惑（中文版）》的清晰电子版，于是改变路线，看起这本书来了。真是不看不知道，一看吓一跳！里面有 95 个 Java 谜题，一点点地看了之后，我是既惭愧又兴奋，因为里面的题真的是&#8220;莫名其妙&#8221;，直白点就是：十有八九是想都想不出来的，&#8857;﹏&#8857;b&#8230;想要真正掌握 Java ，我觉得《Java 解惑》是不得不看的。大多谜题可谓是前所未见的炸弹，一不小心就 over 了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">快点切入正题，如文章标题所示，我从《Java 解惑》中似乎认识到了几个名词，之所以用似乎修饰，因为重载、重写、隐藏这几个接触过了，而遮蔽、遮掩或许是见过但也就忘光了。就整理一下文中的一些与此相关的 Java 谜题用自己的理解描述一下吧。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>重载（overload）：</strong>同一个类中名字相同但参数列表不同的多个方法之间的关系。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">关于重载，是我们比较熟悉的了，最常见的就是运用在类的多个构造函数中，看一下 Java 帮助文档，就可以明白这一情况了。而在《Java 解惑》中，作者给出了下面一个谜题：</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>public&nbsp;class&nbsp;Confusing&nbsp;{&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Confusing(Object&nbsp;o)&nbsp;{&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Object");&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Confusing(double[]&nbsp;dArray)&nbsp;{&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("double&nbsp;array");&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Confusing(<span style="background-color: #ffff00; "><a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81378.html?id=3837#" in_rurl="http://www.textsrv.com/click?v=VVM6MTg4NDU6MTQzOTpudWxsOmUwZTFhNGI4NDhiYzI2MzU2OTNhMzRlYzQ5MDI4MmJjOnotMTA0Ny0xNDIxMjp3d3cuamF2YTN6LmNvbQ%3D%3D" style="font-family: Tahoma; color: #0066ff; ">null</a></span>);&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li><li>}&nbsp;&nbsp;</li></ol>                       </pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">问此时 main() 中将会输出什么？初初一看，并没有多分析就觉得应该是输出&#8220;Object&#8221;，虽然Java中的数组实际上也是引用类型，但毕竟Object 是所有类的最终父类，而且目前 JDK 就连参数中的基本数据类型变量也可以被自动想上转型成包装类而成为 Object 的子类。于是我保守一点地就认为参数 null 应该是匹配到 Object 那个重载方法去了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">可是这答案是错的，JVM 对于重载方法的解析是这样的：<span style="background-color: #ffff00; ">先找出方法名匹配的所有可能的方法；然后根据传进来的形参再次筛选出可能的重载方法；最后才是在这些方法中匹配到一个<strong>最精确</strong>的一个方法。</span>于是，上面的那个谜题就变成确定哪一个才是最精确这一点子上了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">而关于如何判断最精确，有这样的机制：<span style="background-color: #ffff00; ">如果某个重载方法能够接收所有传递给另一个重载方法的实参类型，那么对于参数列表来看，显然后者至少是前者的子集，当然也就更精确了。</span></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">回到谜题上来，Confusing(Object)可以接受任何传递给 Confusing(double[ ])的参数（任何数组引用最终能够都是 Object 对象），因此 main() 中的 null 应该是被 JVM 匹配到 Confusing(double[ ]) 中，也就有了与我所认为的结果相反的输出了。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>小结：</strong>这个谜题表明了我们在写重载方法时，最好是明确地区分出各个方法中的参数列表，不要让彼此之间有互相包含、模糊不清的关系。虽然重载是为了在相同名字的方法中传入实参，由 JVM 动态解析选择合适的方法，但有时也很容易陷入这种方便背后所带来的地雷区当中。其中一种可行的办法就是，<span style="background-color: #ffff00; ">提供不同的方法名</span>。但是构造函数的名字一定得相同的啊？</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">实际上，在《重构与模式》第六章中，作者用他自身的项目经验对&#8220;创建&#8221;这一话题展开了讲解，就算是构造函数，也有很好的重构手法将其清晰地区分开来，不使用重载而是用不同名称的方法，将原本需要重载的构造函数委托给具有最大完整参数列表的私有构造函数中。又是一本经典，值得看哦&#8230;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>重写（override）：</strong>父类中的<strong>实例方法</strong>被其子类重新实现。既然是实例方法，那就是非 static 修饰的了，否则就是 static 静态方法了，那叫做<strong>类方法</strong>。在我看来，正是重写这一机制的存在，才为多态机制提供了基础。或许 implements （实现）一个 interface （接口）中所声明的方法也能成为重写，因为 interface 的一部分存在原因也是为了多态。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">对于重写，在《Java 解惑》中有下面这个谜题让我明白：<strong>绝对不能在构造函数中调用可能会被子类重写的方法。</strong></p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>class&nbsp;Point&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;final&nbsp;int&nbsp;x,&nbsp;y; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;String&nbsp;name; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;Point(int&nbsp;x,&nbsp;int&nbsp;y)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.x&nbsp;=&nbsp;x; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.y&nbsp;=&nbsp;y; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff00; ">name&nbsp;=&nbsp;makeName(); &nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;String&nbsp;makeName()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;"["&nbsp;+&nbsp;x&nbsp;+&nbsp;","&nbsp;+&nbsp;y&nbsp;+&nbsp;"]"; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;final&nbsp;String&nbsp;toString()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;name; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>} &nbsp;</li><li>&nbsp;</li><li>public&nbsp;class&nbsp;ColorPoint&nbsp;extends&nbsp;Point&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;String&nbsp;color; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;ColorPoint(int&nbsp;x,&nbsp;int&nbsp;y,&nbsp;String&nbsp;color)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(x,&nbsp;y); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff00; ">this.color&nbsp;=&nbsp;color;</span> &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;String&nbsp;makeName()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;super.makeName()&nbsp;+&nbsp;":"&nbsp;+&nbsp;color; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(new&nbsp;ColorPoint(4,&nbsp;2,&nbsp;"purple")); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>}&nbsp;</li></ol>                       </pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">此时程序运行结果并不是我们所想的 [4,2]:purple ，而是 [4,2]:null 。为什么会这样？看看下面用流程标号注释过的代码，就能理解了。</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; "><ol><li>class&nbsp;Point&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;final&nbsp;int&nbsp;x,&nbsp;y; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;String&nbsp;name; &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;Point(int&nbsp;x,&nbsp;int&nbsp;y)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.x&nbsp;=&nbsp;x; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.y&nbsp;=&nbsp;y; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;makeName();//&nbsp;3.&nbsp;由于被子类重写过的makeName() &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;String&nbsp;makeName()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;"["&nbsp;+&nbsp;x&nbsp;+&nbsp;","&nbsp;+&nbsp;y&nbsp;+&nbsp;"]"; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;final&nbsp;String&nbsp;toString()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;name; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>} &nbsp;</li><li>&nbsp;</li><li>public&nbsp;class&nbsp;ColorPoint&nbsp;extends&nbsp;Point&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;String&nbsp;color; &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;ColorPoint(int&nbsp;x,&nbsp;int&nbsp;y,&nbsp;String&nbsp;color)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(x,&nbsp;y);&nbsp;//&nbsp;2.&nbsp;调用Point父类构造函数 &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.color&nbsp;=&nbsp;color;&nbsp;//&nbsp;5.&nbsp;初始化&nbsp;color&nbsp;，可是已经太晚了... &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;String&nbsp;makeName()&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;4.&nbsp;问题来了：它在子类构造函数之前调用了 &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;而此时的&nbsp;color&nbsp;是&nbsp;null&nbsp;的啊！！！ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;super.makeName()&nbsp;+&nbsp;":"&nbsp;+&nbsp;color; &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1.&nbsp;调用ColorPoint子类构造函数 &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(new&nbsp;ColorPoint(4,&nbsp;2,&nbsp;"purple")); &nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;</li><li>}&nbsp;</li></ol>                       </pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">思路很清晰了，ColorPoint 子类中的构造函数中的 this.color = color; 还未被执行到就将 null 作为 String color 的值了。正是因为这种来来回回的调用使得程序变得不正常了，在我看来，有那么一点类似于&#8220;回调&#8221;的意思。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">要去除这种代码结构的不合理，最好还是把 Point 父类构造函数中调用 makeName() 方法一句去掉，然后在 toString&nbsp; 中判断并调用 makeName() 来为 name 初始化，如下：</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>小结：</strong>重写对于多态固然重要，但是设计出不正确的代码结构的话，原本想要的多态就会被扭曲甚至造成反效果。于是，绝对不要在构造函数中调用可能会被子类重写的方法。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;好像文字太多的文章看了容易使人晕乎乎的，啰啰嗦嗦、模模糊糊地才写了两个词儿，还是分开来写吧。其实，看了一部分《Java 解惑》才明白还有好多好多 Java 里面该注意的要点。要想在适当的时候辨清各种语法上、机制上的知识点，难啊！</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">记得高中语文课上读过一片抒情的散文，标题为&#8220;哦&#8212;&#8212;香雪！&#8221;而我看了《Java 解惑》，想说&#8220;噢&#8212;&#8212;Java！&#8221;~~~~(&amp;gt;_&amp;lt;)~~~~</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>总结：</strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1、在我们编程领域，好书真的是一大把，就看自己有没时间、有没策略地去吸收了；</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2、有时候看好书时留意作者对其他书籍的&#8220;友情链接&#8221;，或者出版社推荐的相关书籍，这样就能够免去自己慢慢搜寻好书的过程了，O(&#8745;_&#8745;)O哈！</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">本文出自 &#8220;蚂蚁&#8221; 博客，请务必保留此出处http://haolloyin.blog.51cto.com/1177454/372691</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:59 <a href="http://www.cppblog.com/chenglong7997/articles/170899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 静态数据</title><link>http://www.cppblog.com/chenglong7997/articles/170898.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:57:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170898.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170898.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170898.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170898.html</trackback:ping><description><![CDATA[<span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp; 前面讨论的this关键字，典型地反映了随着对象引用的不同，其变量和操作亦不同，体现了面向对象编程的内涵。但是，有时在程序中的要求正好与此相反&#8212;&#8212;需要代表整个类的数据。Java提供的静态数据（static data）就是专门用来实现这一要求的。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span class="STYLE1" style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">二、类数据</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;静态数据属于全体对象，是所有对象共享的数据，或类数据。静态常量也称为类常量；静态变量也称类变量。在解决实际问题中经常会遇到类数据。例如，Math.PI，Math.E对所有对象的算术运算都是一样的，它们被定义为Math类的静态常量。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; 再例如，税收比率在计算税款时对所有定义的对象都适用，也是静态数据的典型例子。有时，我们需要统计创建了多少个对象，或者有多少个对象调用了某个方法，或者应用了某个操作等等，这需要在程序中使用静态数据来完成这些任务。类数据可以是private或public。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">如下是定义静态数据的典型例子。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">例1．定义静态变量。</span>&nbsp;<br /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static double accountLimit; //定义一个双精度静态变量&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static int userCount = 0; //定义一个整数静态变量并赋值</span>&nbsp;<br /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static String welcome = "Java is hot!"; //定义一个字符串静态变量并赋值</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">例2．定义静态常量。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">private static final float TAX_RATE = 0.0875f; //定义一个浮点静态常量</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static final double EARTH_MASS = 5.972e24; //定义一个双精度静态常量</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public static final int MONTH_IN_YEAR = 12; //定义一个整数静态常量</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">注意 静态常量必须在定义时赋值。否则为非法。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如下是使用静态数据的典型例子：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public FutureValue() { //构造器</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;//对对象数据初始化的各语句</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;...</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;userCount++； //每创建一个对象，都对原来统计用户数目的静态变量userCount加1</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">}</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public FutureValue(String name) {</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;this.name = name;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;//对其他各变量初始化的语句</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;...</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;userCount++; //同上</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">}</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">以上例子表示无论以哪个构造器创建对象，对静态变量userCount都执行加1，达到统计对象的目的。如果执行下列输出语句：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">System.out.println(myFutureValue.getUserCount()); //用对象调用</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">其输出值与：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">System.out.pritnln(FutureValue.getUserCount()); //用静态方法通过类直接调用</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">完全一样。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">静态数据通常由静态方法来调用。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">三、 属于所有对象</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;静态数据为什么属于整个类，或类中的所有对象呢？这是因为它们被储存在特殊指定的存储器中。进一步讲，静态数据储存在类访问区的储存空间。这个储存空间是这个类代表的所有对象共享的，它的访问生命期和这个类相同。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; 而实例数据分别储存在代表每个对象的一段存储区域中。假设我们创建了100个对象，那么将有100个这样的储存区域存在。即每个对象都有它自己独立存储区域，用来存储它所具有的所有实例数据。这个存储区域的访问生命期和对象相同。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">四、静态数据原则</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;静态数据是类的组成部分，确定静态数据首先从类的设计入手，分析和确定类的应用范畴，它所执行的运算和操作，包括确定数学公式以及运算逻辑等。由此来确定静态数据和实例数据。静态数据与实例数据本质的不同在于：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">（1） 实例数据是在这个类的应用中，每个对象，或大多数对象都具有的、但各自有不同值的数据。例如，在计算投资回报的程序中，每个对象都有姓名（name）、月投资额（monthlyInvest），年投资回报率（yearlyRate），以及投资年（years），但这些数据的值对每个对象来说，是完全由对象来确定的，与整个类无关；与具体对象的形态有关。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">（2） 静态数据是所有对象共享的数据。在这个类的应用中，无论哪一个对象，如果应用这个数据的话，都必须具有相同的值，或者这个数据对所有对象都有意义，或者这个数据代表了所有对象的形态表征，与整个类有关。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">根据以上分析，确定静态数据可根据如下原则：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">1． 对类中的对象进行统计的数据应该确定为静态数据。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">2． 对类中所有对象，设置上下限的数据，应该确定为静态常量数据。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3． 在执行运算的公式和解决问题的逻辑中，某个常量对类中所有的对象，如果有相同应用，这个常量应该确定为静态常量数据。</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">4． 用来对类中所有对象进行提示、询问、问候以及其他与具体对象无关的信息或数据，应该确定为静态常量数据。</span>&nbsp;<img src ="http://www.cppblog.com/chenglong7997/aggbug/170898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:57 <a href="http://www.cppblog.com/chenglong7997/articles/170898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java重写方法的原则</title><link>http://www.cppblog.com/chenglong7997/articles/170896.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:55:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170896.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170896.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170896.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170896.html</trackback:ping><description><![CDATA[<span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp;若想实现一个合格重写方法，而不是重载，那么必须同时满足下面的要求！&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">A、重写规则之一：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;重写方法不能比被重写方法限制有更严格的访问级别。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">（但是可以更广泛，比如父类方法是包访问权限，子类的重写方法是public访问权限。） 比如：Object类有个toString()方法，开始重写这个方法的时候我们总容易忘记public修饰符，编译器当然不会放过任何教训我们 的机会。出错的原因就是：没有加任何访问修饰符的方法具有包访问权限，包访问权限比public当然要严格了，所以编译器会报错的。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">B、重写规则之二</span><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;参数列表必须与被重写方法的相同。&nbsp;</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; text-align: -webkit-left; background-color: #ffffff; ">重写有个孪生的弟弟叫重载，也就是后面要出场的。如果子类方法的参数与父类对应的方法不同，那么就是你认错人了，那是重载，不是重写。</span>&nbsp;<br /><br /><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">C、重写规则之三：</span><br />&nbsp;&nbsp; 返回类型必须与被重写方法的返回类型相同。<br />父类方法A：void eat(){} 子类方法B：int eat(){} 两者虽然参数相同，可是返回类型不同，所以不是重写。<br />父类方法A：int eat(){} 子类方法B：long eat(){} 返回类型虽然兼容父类，但是不同就是不同，所以不是重写。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">D、重写规则之四：</span><br />&nbsp;&nbsp; 重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少，更有限或者不抛出异常。<br />import java.io.*;<br />public class Test {<br />&nbsp;&nbsp;public static void main (String[] args) {<br />&nbsp;&nbsp;&nbsp;Animal h = new Horse();<br />&nbsp;&nbsp;&nbsp;try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h.eat();&nbsp;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;catch (Exception e) {<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;}<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Animal {<br />&nbsp;&nbsp;public void eat() throws Exception{<br />&nbsp;&nbsp;&nbsp;System.out.println ("Animal is eating.");<br />&nbsp;&nbsp;&nbsp;throw new Exception();<br />&nbsp;&nbsp;}<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Horse extends Animal{<br />&nbsp;&nbsp;&nbsp;public void eat() throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println ("Horse is eating.");<br />&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException();<br />&nbsp;&nbsp;}<br />}<br /><br />这个例子中，父类抛出了检查异常Exception，子类抛出的IOException是Exception的子类，也即是比被重写的方法抛出了更有限的异常，这是可以的。如果反过来，父类抛出IOException，子类抛出更为宽泛的Exception，那么不会通过编译的。<br />注意：这种限制只是针对检查异常，至于运行时异常RuntimeException及其子类不再这个限制之中。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">E、重写规则之五：</span><br />&nbsp;&nbsp; 不能重写被标识为final的方法。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">F、重写规则之六：</span><br />&nbsp;&nbsp;如果一个方法不能被继承，则不能重写它。<br />比较典型的就是父类的private方法。下例会产生一个有趣的现象。<br />public class Test {<br />&nbsp;&nbsp;public static void main (String[] args) {<br />&nbsp;&nbsp;&nbsp;//Animal h = new Horse();<br />&nbsp;&nbsp;&nbsp;Horse h = new Horse();<br />&nbsp;&nbsp;&nbsp;&nbsp;h.eat();<br />&nbsp;&nbsp;&nbsp;}<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Animal {<br />&nbsp;&nbsp;&nbsp;private void eat(){<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println ("Animal is eating.");<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">class Horse extends Animal{<br />&nbsp;&nbsp;&nbsp;public void eat(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println ("Horse is eating.");<br />&nbsp;&nbsp;&nbsp;}<br />}<br />这段代码是能通过编译的。表面上看来违反了第六条规则，但实际上那是一点巧合。Animal类的eat()方法不能被继承，因此Horse类中的 eat()方法是一个全新的方法，不是重写也不是重载，只是一个只属于Horse类的全新的方法！这点让很多人迷惑了，但是也不是那么难以理解。<br />main()方法如果是这样：<br />Animal h = new Horse();<br />//Horse h = new Horse();<br />h.eat();<br />编译器会报错，为什么呢？Horse类的eat()方法是public的啊！应该可以调用啊！请牢记，多态只看父类引用的方法，而不看子类对象的方法！</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:55 <a href="http://www.cppblog.com/chenglong7997/articles/170896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java的null</title><link>http://www.cppblog.com/chenglong7997/articles/170895.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:51:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170895.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170895.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170895.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170895.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170895.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="text-align: -webkit-left; ">一、null是代表不确定的对象</span><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">&nbsp;&nbsp;&nbsp;&nbsp;Java中，null是一个关键字，用来标识一个不确定的对象。因此可以将null赋给引用类型变量，但不可以将null赋给基本类型变量。</span><br style="text-align: -webkit-left; " /><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">比如：int a =&nbsp;</span><a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article8/81435.html?id=4312#" in_rurl="http://www.textsrv.com/click?v=VVM6MTg4NDU6MTQzOTpudWxsOmUwZTFhNGI4NDhiYzI2MzU2OTNhMzRlYzQ5MDI4MmJjOnotMTA0Ny0xNDIxMjp3d3cuamF2YTN6LmNvbQ%3D%3D" style="color: #0066ff; text-align: -webkit-left; ">null</a><span style="text-align: -webkit-left; ">;是错误的。Ojbect o = null是正确的。</span><br style="text-align: -webkit-left; " /><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">&nbsp;&nbsp;Java中，变量都遵循一个原则，先定义，并且初始化后，才可以使用。我们不能int a后，不给a指定值，就去打印a的值。</span><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">这条对对于引用类型变量也是适用的。</span><br style="text-align: -webkit-left; " /><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">&nbsp;&nbsp;&nbsp;有时候，我们定义一个引用类型变量，在刚开始的时候，无法给出一个确定的值，但是不指定值，程序可能会在try语句块中初始化值。</span><br style="text-align: -webkit-left; " /><span style="text-align: -webkit-left; ">&nbsp;&nbsp;&nbsp;&nbsp;我们下面使用变量的时候就会报错。这时候，可以先给变量指定一个null值，问题就解决了。例如：</span>&nbsp;<br />Connection conn = null;<br />try {<br />&nbsp;&nbsp;&nbsp;conn = DriverManager.getConnection("url", "user", "password");<br />} catch (SQLException e) {<br />&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />}<br /><br />String catalog = conn.getCatalog();<br /><br />如果刚开始的时候不指定conn = null，则最后一句就会报错。<br /><br />二、null本身不是对象，也不是Objcet的实例<br /><br />&nbsp;&nbsp;null本身虽然能代表一个不确定的对象，但就null本身来说，它不是对象，也不知道什么类型，也不是java.lang.Object的实例。<br />可以做一个简单的例子：<br /><br />//null是对象吗? 属于Object类型吗?<br />if (null instanceof java.lang.Object) {<br />&nbsp;&nbsp;System.out.println("null属于java.lang.Object类型");<br />} else {<br />&nbsp;&nbsp;System.out.println("null不属于java.lang.Object类型");<br />}<br /><br />结果会输出：null不属于java.lang.Object类型<br /><br />三、Java默认给变量赋值<br /><br />在定义变量的时候，如果定义后没有给变量赋值，则Java在运行时会自动给变量赋值。<br />赋值原则是整数类型int、byte、short、 long的自动赋值为0，带小数点的float、double自动赋值为0.0，<br />boolean的自动赋值为false，其他各供引用类型变量自动赋值为 null。<br />这个具体可以通过调试来看。<br /><br />四、容器类型与null<br /><br />List：允许重复元素，可以加入任意多个null。<br />Set：不允许重复元素，最多可以加入一个null。<br />Map：Map的key最多可以加入一个null，value字段没有限制。<br />数组：基本类型数组，定义后，如果不给定初始值，则java运行时会自动给定值。<br />引用类型数组，不给定初始值，则所有的元素值为null。<br /><br />五、null的其他作用<br /><br />1、判断一个引用类型数据是否null。 用==来判断。<br />2、释放内存，让一个非null的引用类型变量指向null。这样这个对象就不再被任何对象应用了。<br />等待JVM垃圾回收机制去回收。<br /><br />以下是我的一些想法：<br />package com.zac.expe1;<br /></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public class NullInDepth {<br />&nbsp;&nbsp; public static void helloThere(){<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Hello from null?!");<br />&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//((NullInDepth)null).helloThere();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NullInDepth nullIn = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nullIn.helloThere();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object nullStr = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NullInDepth nullOut = (NullInDepth) nullStr;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(nullIn);<br />&nbsp;&nbsp;&nbsp;}<br /><br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">这里Hello from null?!会被打印出来，而后边一句会打印出null，<br />我们知道println一般是调用对象的toString来进行打印，但是null明显不是对象，<br />作为一个不确定引用它只是把自己的literal给打印了出来，因此我猜测null是预先存储在内存中的一个引用，<br />它是有值的，可能根据不同的jvm有不同的实现，但是jvm中会一致地将这个值打印为null。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><br />另外按照我的猜测，null应该是栈里边的一个引用，null type是可以转换为所有其他type的引用，<br />所以我也猜测null type应该是所有其他引用类型的子类型。&nbsp;<br />静态方法（也许需要是public的）应该是由类名来调用，但是也可以使用 类名(null).静态方法名的方式调用。</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:51 <a href="http://www.cppblog.com/chenglong7997/articles/170895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java浅/深复制</title><link>http://www.cppblog.com/chenglong7997/articles/170893.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:48:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170893.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170893.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170893.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170893.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">&#9332;浅复制(浅克隆)</span><br />&nbsp;&nbsp;&nbsp; 被复制对象的所有变量都含有与原来的对象相同的值，而所有的对其他对象的引用仍然指向原来的对象。换言之，浅复制仅仅复制所考虑的对象，而不复制它所引用的对象。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><span style="color: #0000ff; ">&#9333;深复制(深克隆)</span><br />&nbsp;&nbsp; 被复制对象的所有变量都含有与原来的对象相同的值，除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象，而不再是原有的那些被引用的对象。换言之，深复制把要复制的对象所引用的对象都复制了一遍。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Java的clone()方法</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9332;clone方法将对象复制了一份并返回给调用者。一般而言，clone()方法满足：</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9312;对任何的对象x，都有x.clone() !=x//克隆对象与原对象不是同一个对象</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9313;对任何的对象x，都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9314;如果对象x的equals()方法定义恰当，那么x.clone().equals(x)应该成立。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9333;Java中对象的克隆</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9312;为了获取对象的一份拷贝，我们可以利用Object类的clone()方法。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9313;在派生类中覆盖基类的clone()方法，并声明为public。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9314;在派生类的clone()方法中，调用super.clone()。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9315;在派生类中实现Cloneable接口。</p><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">请看如下代码：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">    class Student implements Cloneable        {            String name;            int age;             Student(String name,int age)            {                this.name=name;                this.age=age;            }           public Object clone()           {              Object o=null;              try              {              o=(Student)super.clone();//Object中的clone()识别出你要复制的是哪一              // 个对象。               }               catch(CloneNotSupportedException e)              {                  System.out.println(e.toString());              }              return o;          }            public static void main(String[] args)          {            Student s1=new Student("zhangsan",18);            Student s2=(Student)s1.clone();            s2.name="lisi";            s2.age=20;          System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后，不影响学生1的值。         }     }<br />运行结果：<br />C:\java&gt;java   Student<br />name=zhangsan,age=18<br /><br />说明：</pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9312;为什么我们在派生类中覆盖Object的clone()方法时，一定要调用super.clone()呢?在运行时刻，Object中的 clone()识别出你要复制的是哪一个对象，然后为此对象分配空间，并进行对象的复制，将原始对象的内容一一复制到新对象的存储空间中。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&#9313;继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">    class Professor        {            String name;            int age;            Professor(String name,int age)            {                this.name=name;                this.age=age;            }       }        public class Student implements Cloneable     {         String name;//常量对象。         int age;         Professor p;//学生1和学生2的引用值都是一样的。         Student(String name,int age,Professor p)         {             this.name=name;             this.age=age;             this.p=p;         }        public Object clone()         {             Student o=null;            try             {                o=(Student)super.clone();             }             catch(CloneNotSupportedException e)            {                System.out.println(e.toString());            }             return o;         }           public static void main(String[] args)         {           Professor p=new Professor("wangwu",50);           Student s1=new Student("zhangsan",18,p);           Student s2=(Student)s1.clone();            s2.p.name="lisi";            s2.p.age=30;      System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授成为lisi,age为30。      } }</pre><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">运行结果：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">C:\java&gt;java Student</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">name=lisi,age=30</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">那应该如何实现深层次的克隆，即修改s2的教授不会影响s1的教授，代码改进如下。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">改进使学生1的Professor不改变(深层次的克隆)</p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">    class Professor implements Cloneable        {            String name;            int age;         Professor(String name,int age)            {                this.name=name;                this.age=age;            }             public Object clone()           {               Object o=null;               try              {                   o=super.clone();              }              catch(CloneNotSupportedException e)              {                  System.out.println(e.toString());             }             return o;         }     }     public  class Student implements Cloneable       {           String name;           int age;           Professor p;           Student(String name,int age,Professor p)          {              this.name=name;              this.age=age;              this.p=p;          }       public Object clone()          {               Student o=null;               try               {                 o=(Student)super.clone();             }             catch(CloneNotSupportedException e)             {                 System.out.println(e.toString());             }            o.p=(Professor)p.clone();            return o;         }         public static void main(String[] args)        {          Professor p=new Professor("wangwu",50);          Student s1=new Student("zhangsan",18,p);          Student s2=(Student)s1.clone();           s2.p.name="lisi";           s2.p.age=30;      System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变。      } }   </pre><p style="color: #0000ff; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">3.利用串行化来做深复制</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;把对象写到流里的过程是串行化(Serilization)过程，但是在Java程序师圈子里又非常形象地称为&#8220;冷冻&#8221;或者&#8220;腌咸菜 (picking)&#8221;过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做&#8220;解冻&#8221;或者&#8220;回鲜(depicking)&#8221;过程。应当指出的是，写在流里的是对象的一个拷贝，而原对象仍然存在于JVM里面，因此&#8220;腌成咸菜&#8221;的只是对象的一个拷贝，Java咸菜还可以回鲜。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">在Java语言里深复制一个对象，常常可以先使对象实现Serializable接口，然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜)，再从流里读出来(把咸菜回鲜)，便可以重建对象。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">如下为深复制源代码。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">public Object deepClone()&nbsp;<br />{&nbsp;<br />&nbsp;&nbsp;//将对象写到流里&nbsp;<br />&nbsp;&nbsp;ByteArrayOutputStream bo=new ByteArrayOutputStream();&nbsp;<br />&nbsp;&nbsp;ObjectOutputStream oo=new ObjectOutputStream(bo);&nbsp;<br />&nbsp;&nbsp;oo.writeObject(this);&nbsp;<br /><br />&nbsp;&nbsp;//从流里读出来&nbsp;<br />&nbsp;&nbsp;ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());&nbsp;<br />&nbsp;&nbsp;ObjectInputStream oi=new ObjectInputStream(bi);&nbsp;<br />&nbsp;&nbsp;return(oi.readObject());&nbsp;<br />}</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的，否则，就需要仔细考察那些不可串行化的对象可否设成transient，从而将之排除在复制过程之外。上例代码改进如下。<br /></p><pre style="color: #666666; font-size: 12px; line-height: normal; background-color: #ffffff; ">import java.io.*;         class Professor implements Serializable        {            String name;            int age;            Professor(String name,int age)            {                this.name=name;                this.age=age;            }        }        public  class Student implements Serializable       {           String name;//常量对象。           int age;           Professor p;//学生1和学生2的引用值都是一样的。            Student(String name,int age,Professor p)         {             this.name=name;             this.age=age;             this.p=p;        }      public Object deepClone() throws IOException, OptionalDataException,ClassNotFoundException       {       //将对象写到流里       ByteArrayOutputStream bo=new ByteArrayOutputStream();       ObjectOutputStream oo=new ObjectOutputStream(bo);       oo.writeObject(this);          //从流里读出来       ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());       ObjectInputStream oi=new ObjectInputStream(bi);       return(oi.readObject());       }                  public static void main(String[] args) throws IOException,ClassNotFoundException       {            Professor p=new Professor("wangwu",50);            Student s1=new Student("zhangsan",18,p);            Student s2=(Student)s1.deepClone();            s2.p.name="lisi";            s2.p.age=30;           System.out.println("name="+s1.p.name+","+"age="+s1.p.age); //学生1的教授不改变。      }   }</pre><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "></p><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">运行结果：</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">C:\java&gt;java Student</span><br style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; " /><span style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">name=wangwu,age=50</span>&nbsp;<img src ="http://www.cppblog.com/chenglong7997/aggbug/170893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:48 <a href="http://www.cppblog.com/chenglong7997/articles/170893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序易遭受逆向工程攻击的原因</title><link>http://www.cppblog.com/chenglong7997/articles/170892.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:43:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170892.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170892.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170892.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170892.html</trackback:ping><description><![CDATA[<div>&nbsp;Java应用程序虽然能够&#8220;编写一次，随处运行&#8221;（Write Once, Run Anywhere）是一个巨大的优势，但这种环境的架构方式使其远比本机应用程序更容易被黑客进行逆向工程。这意味着开发人员面临着失去知识产权的非常真实的危险。基于应用程序的虚拟机比本机应用程序更容易逆向工程的原因有很多：</div><div><span style="color: red; ">JVM是开源的</span><br />&nbsp; Sun已经免费提供JVM的源代码。这使得黑客只需查看代码即可弄清虚拟机的工作方式。</div><div>Java .class文件格式是可公开获取的<br />如前所述，Java源代码被编译成字节码，而字节码存储在Java .class文件中。Java .class文件格式的规范是可公开获取的，因此有技术背景的任何人都能容易地编写可以处理、修改或转换.class文件的工具。</div><div><span style="color: red; ">JVM是软件，而不是硬件</span></div><div>&nbsp; &nbsp;与需要理解特定处理器的专家使用的标准编程语言不同，JVM是一个应用程序，它如同微处理器一样运作，并使用操作系统和计算机硬件提供的内置功能。由于黑客不必深入到硬件级别，因此更容易取得对JVM的完全控制。</div><div>&nbsp; &nbsp;因此，例如在使用标准本机系统开发语言进行调试时，暂停处理器极为困难，需要具备处理器、调试功能及可用环调试器的专家知识。但是，由于JVM 运行环境的源代码是可公开获取的，因此开发人员可以轻松地建立自己的虚拟机来完全控制虚拟处理器的各个方面。这样可以容易地分析运行环境中运行的每个应用程序。</div><div><span style="color: red; ">Java的指令比本机代码少</span></div><div>&nbsp; &nbsp;然而，JVM代码易于进行反向工程的另一个原因是它具有比本地应用程序更少的指令。这是出于性能考虑。JVM的使用在应用程序和本机处理器之间增加了一个软件层，这会对性能产生负面影响。虽然现代处理器不断提高的执行速度最终将缓解这一问题，但这一问题仍然很明显。虚拟机开发人员提高执行速度的一种方法是使用比本机处理器汇编程序更小的字节码指令集。本机应用程序可能包含多达400条指令，而Java应用程序通常使用不超过200条的指令。更少的指令意味着黑客可以更快地分析代码以进行逆向工程。这些特性使得虚拟机远比其它类型的应用程序更容易遭受逆向工程攻击。</div><div><span style="color: red; ">第三方反汇编程序增加了漏洞</span></div><div>&nbsp;不仅是JVM本身容易遭受逆向工程攻击，商业和免费的Java字节码反汇编程序也越来越多，从而进一步简化了代码逆向工程的过程。IDA和Eclipse字节码插件是众多Java字节码反汇编程序中的两种。作为商业产品，IDA是一种普遍的反汇编程序，可用于许多不同的处理器，包括80x86和MIPS。Eclipse字节码插件是免费软件。它能够反编译Java .class文件的字节码并以适当的顺序显示所有操作码指令。&nbsp;尽管这些产品不大可能从字节码完美地恢复原始代码，但它们恢复的源代码将等同于原始代码，并且比字节码更具可读性。一旦恢复了源代码，攻击者可以容易地删除部分代码并将其非法地用于竞争对手的应用程序中，或在.class文件中定位打补丁。</div><div></div><div>图1提供了黑客可能如何在.class文件中打补丁的一个示例。屏幕的上半部分显示了一小段Java源代码。屏幕的下半部分显示了字节码反汇编的输出，也就是一个字节码指令列表。标记为红色的区域是源代码中IF结构的对应指令。字节码指令&#8220;LCMP&#8221;的十六进制表示为0x94。该工具还指出了操作码在.class文件中的位置。有了这些信息，黑客可以使用简单的十六进制编辑器来改变该IF分支，而这只需不到一分钟的时间。假设该IF条件用于许可证检查，黑客可倒置该条件，指示即使在许可证被验证为无效（如已过期）的情况下仍返回&#8220;True&#8221;，从而突破许可证检查。在这种情况下，黑客使用一个字节的补丁即可完成所有工作。虽然大多数应用程序都比这个示例更加复杂，但即使在复杂的应用程序中，字节码也非常简单并且容易理解。</div><div></div><div>&nbsp;Java应用程序虽然能够&#8220;编写一次，随处运行&#8221;（Write Once, Run Anywhere）是一个巨大的优势，但这种环境的架构方式使其远比本机应用程序更容易被黑客进行逆向工程。这意味着开发人员面临着失去知识产权的非常真实的危险。基于应用程序的虚拟机比本机应用程序更容易逆向工程的原因有很多：</div><div></div><div><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><img src="http://www.java3z.com/cwbwebhome/article/article8/img7/161822209.jpg" width="392" height="279"  alt="" /></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">图1 - 用于字节码反汇编的Eclipse字节码插件</p></div><div></div><div></div><img src ="http://www.cppblog.com/chenglong7997/aggbug/170892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:43 <a href="http://www.cppblog.com/chenglong7997/articles/170892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java基本功——Reference</title><link>http://www.cppblog.com/chenglong7997/articles/170891.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Wed, 11 Apr 2012 05:30:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/170891.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/170891.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/170891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/170891.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/170891.html</trackback:ping><description><![CDATA[<p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;这是一篇一年多之前便已写就的文章，那时，因为很多Java程序员只求追随新生的事物，却连基本的概念都没有，很多讨论中，很明显是基本功不过硬，于是萌生写一个系列文章，讨论Java的基本功，下面便是在这个想法下催生出的第一篇文章。可事实上，真正完成的也只有这一篇。因为未能及时发布，它就被我遗忘在硬盘的角落中。今天，JavaEye上关<a href="http://forum.javaeye.com/viewtopic.php?t=12961" style="color: #0066ff; text-decoration: none; ">于Java传值还是传引用</a>的论战让我记起了自己曾经写过的这篇文章，愿与大家共享。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>Java基本功&#8212;&#8212;Reference</strong></p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">有这样一种说法，如今争锋于IT战场的两大势力，MS一族偏重于底层实现，Java一族偏重于系统架构。说法根据无从考证，但从两大势力各自的社区力量和图书市场已有佳作不难看出，此说法不虚。于是，事情的另一面让人忽略了。<br />偏巧，我是一个喜欢探究底层实现的Java程序员，虽然我的喜好并非纯正咖啡，剑走偏锋却别是一番风味。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>Reference</strong><br />Java世界泰山北斗级大作《Thinking In Java》切入Java就提出&#8220;Everything is Object&#8221;。在Java这个充满Object的世界中，reference是一切谜题的根源，所有的故事都是从这里开始的。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>Reference是什么？<br /></strong>如果你和我一样在进入Java世界之前曾经浪迹于C/C++世界，就一定不会对指针陌生。谈到指针，往日种种不堪回首的经历一下子涌上心头，这里不是抱怨的地方，让我们暂时忘记指针的痛苦，回忆一下最初接触指针的甜蜜吧！还记得你看过的教科书中，如何讲解指针吗？留在我印象中的一种说法是，指针就是地址，如同门牌号码一样，有了地址，你可以轻而易举找到一个人家，而不必费尽心力的大海捞针。<br />C++登上历史舞台，reference也随之而来，容我问个小问题，指针和reference区别何在？我的答案来自于在C++世界享誉盛名的《More Effective C++》。</p><ol style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><li>没有null reference。</li><li>reference必须有初值。</li><li>使用reference要比使用指针效率高。因为reference不需要测试其有效性。</li><li>指针可以重新赋值，而reference总是指向它最初获得的对象</li></ol><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; "><strong>设计选择：</strong><br />当你指向你需要指向的某个东西，而且绝不会改指向其它东西，或是当你实作一个运算符而其语法需要无法有指针达成，你就应该选择reference。其它任何时候，请采用指针。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">这和Java有什么关系？<br />初学Java，鉴于reference的名称，我毫不犹豫的将它和C++中的reference等同起来。不过，我错了。在Java中，reference可以随心所欲的赋值置空，对比一下上面列出的差异，就不难发现，Java的reference如果要与C/C++对应，它不过是一个穿着reference外衣的指针而已。<br />于是，所有关于C中关于指针的理解方式，可以照搬到Java中，简而言之，reference就是一个地址。我们可以把它想象成一个把手，抓住它，就抓住了我们想要操纵的数据。如同掌握C的关键在于掌握指针，探索Java的钥匙就是reference。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">一段小程序<br />我知道，太多的文字总是令人犯困，那就来段代码吧！<br />public class ReferenceTricks {<br />&nbsp;&nbsp;public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp; ReferenceTricks r = new ReferenceTricks();<br />&nbsp;&nbsp;&nbsp;&nbsp;// reset integer<br />&nbsp; &nbsp;&nbsp;r.i = 0;<br />&nbsp;&nbsp;&nbsp; System.out.println("Before changeInteger:" + r.i);<br />&nbsp;&nbsp;&nbsp; changeInteger(r);<br />&nbsp; &nbsp;&nbsp;System.out.println("After changeInteger:" + r.i);</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; // just for format<br />&nbsp; &nbsp;&nbsp;System.out.println();<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; // reset integer<br />&nbsp; &nbsp;&nbsp;r.i = 0;<br />&nbsp;&nbsp;&nbsp; System.out.println("Before changeReference:" + r.i);<br />&nbsp; &nbsp;&nbsp;changeReference(r);<br />&nbsp;&nbsp;&nbsp; System.out.println("After changeReference:" + r.i);<br />&nbsp; }</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;private static void changeReference(ReferenceTricks r) {<br />&nbsp; &nbsp;r = new ReferenceTricks();<br />&nbsp;&nbsp; r.i = 5;<br />&nbsp;&nbsp; System.out.println("In changeReference: " + r.i);<br />&nbsp; }</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp; private static void changeInteger(ReferenceTricks r) {<br />&nbsp;&nbsp; r.i = 5;<br />&nbsp;&nbsp; System.out.println("In changeInteger:" + r.i);<br />&nbsp; }</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp; public int i;<br />}<br /><br />对不起，我知道，把一个字段设成public是一种不好的编码习惯，这里只是为了说明问题。<br />如果你有兴趣自己运行一下这个程序，我等你！</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">OK，你已经运行过了吗？结果如何？是否如你预期？下面是我在自己的机器上运行的结果：<br />Before changeInteger:0<br />In changeInteger:5<br />After changeInteger:5</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">Before changeReference:0<br />In changeReference: 5<br />After changeReference:0<br />这里，我们关注的是两个change&#8212;&#8212;changeReference和changeInteger。从输出的内容中，我们可以看出，两个方法在调用前和调用中完全一样，差异出现在调用后的结果。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">糊涂的讲解<br />先让我们来分析一下changeInteger的行为。<br />前面说过了，Java中的reference就是一个地址，它指向了一个内存空间，这个空间存放着一个对象的相关信息。这里我们暂时不去关心这个内存具体如何排布，只要知道，通过地址，我们可以找到r这个对象的i字段，然后我们给它赋成5。既然这个字段的内容得到了修改，从函数中返回之后，它自然就是改动后的结果了，所以调用之后，r对象的i字段依然是5。下图展示了changeInteger调用前后内存变化。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp; Reference +--------+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reference +--------+<br />&nbsp;&nbsp;&nbsp; ----------&gt;| i = 0&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----------&gt;| i = 5&nbsp; |<br />&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;&nbsp;&nbsp;&nbsp;&nbsp; |--------|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Memory |&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; | Memory |<br />&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;<br />&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />&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;&nbsp;&nbsp;&nbsp;&nbsp; +--------+</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;调用changeInteger之前&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;调用changeInteger之后</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">让我们把目光转向changeReference。<br />从代码上，我们可以看出，同changeInteger之间的差别仅仅在于多了这么一句。<br />r = new ReferenceTricks();<br />这条语句的作用是分配一块新的内存，然后将r指向它。<br />执行完这条语句，r就不再是原来的r，但它依然是一个ReferenceTricks的对象，所以我们依然可以对这个r的i字段赋值。到此为止，一切都是那么自然。</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp; Reference +--------+&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; +--------+<br />&nbsp;&nbsp;&nbsp; ----------&gt;| i = 0&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; | i = 0&nbsp; |<br />&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;&nbsp;&nbsp;&nbsp;&nbsp; |--------|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;<a title="Powered by Text-Enhance" id="_GPLITA_0" href="http://www.java3z.com/cwbwebhome/article/article2/2182.html?id=567#" in_rurl="http://www.textsrv.com/click?v=VVM6MTc4MDA6MTMxMjptZW1vcnk6NTgxZTM0YmNmNjdlOTcyMjI3MGUyNWY1Mzc3OWI3ODk6ei0xMDQ3LTE0MjEyOnd3dy5qYXZhM3ouY29t" style="color: #0066ff; ">Memory</a>&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; | Memory |<br />&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;&nbsp; Reference |--------|&nbsp;<br />&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; ----------&gt;| i = 5&nbsp; |<br />&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;&nbsp;&nbsp;&nbsp;&nbsp; +--------+</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;调用changeReference之前&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;调用changeReference之后</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">顺着这个思路继续下去的话，执行完changeReference，输出的r的i字段，那么应该是应该是新内存中的i，所以应该是5。至于那块被我们抛弃的内存，Java的GC功能自然会替我们善后的。<br />事与愿违。<br />实际的结果我们已经看到了，输出的是0。<br />肯定哪个地方错了，究竟是哪个地方呢？</p><p style="color: #666666; font-family: Tahoma; font-size: 12px; line-height: normal; background-color: #ffffff; ">参数传递的秘密<br />知道方法参数如何传递吗？<br />记得刚开始学编程那会儿，老师教导，所谓参数，有形式参数和实际参数之分，参数列表中写的那些东西都叫形式参数，在实际调用的时候，它们会被实际参数所替代。<br />编译程序不可能知道每次调用的实际参数都是什么，于是写编译器的高手就出个办法，让实际参数按照一定顺序放到一个大家都可以找得到的地方，以此作为方法调用的一种约定。所谓&#8220;没有规矩，不成方圆&#8221;，有了这个规矩，大家协作起来就容易多了。这个公共数据区，现在编译器的选择通常是&#8220;栈&#8221;，而所谓的顺序就是形式参数声明的顺序。<br />显然，程序运行的过程中，作为实际参数的变量可能遍布于内存的各个位置，而并不一定要老老实实的呆在栈里。为了守&#8220;规矩&#8221;，程序只好将变量复制一份到栈中，也就是通常所说的将参数压入栈中。<br />打起精神，谜底就要揭晓了。<br />我刚才说什么来着？将变量复制一份到栈中，没错，&#8220;复制&#8221;！<br />这就是所谓的值传递。<br />C语言的旷世经典《The C Programming Language》开篇的第一章中，谈到实际参数时说，&#8220;在C中，所有函数的实际参数都是传&#8216;值'的&#8221;。<br />马上会有人站出来，&#8220;错了，还有传地址，比如以指针传递就是传地址&#8221;。<br />不错，传指针就是传地址。在把指针视为地址的时候，是否考虑过这样一个问题，它也是一个变量。前面的讨论中说过了，参数传递必须要把参数压入栈中，作为地址的指针也不例外。所以，必须把这个指针也复制一份。函数中对于指针操作实际上是对于这个指针副本的操作。<br />Java的reference等于C的指针。所以，在Java的方法调用中，reference也要复制一份压入堆栈。在方法中对reference的操作就是对这个reference副本的操作。<br />谜底揭晓<br />好，让我们回到最初的问题上。<br />在changeReference中对于reference的赋值实际上是对这个reference的副本进行赋值，而对于reference的本尊没有产生丝毫的影响。<br />回到调用点，本尊醒来，它并不知道自己睡去的这段时间内发生过什么，所以只好当作什么都没发生过一般。就这样，副本消失了，在方法中对它的修改也就烟消云散了。<br />&nbsp;<br />也许你会问出这样的问题，&#8220;听了你的解释，我反而对changeInteger感到迷惑了，既然是对于副本的操作，为什么changeInteger可以运作正常？&#8221;<br />呵呵，很有趣的大脑短路现象。<br />好，那我就用前面的说法解释一下changeInteger的运作。<br />所谓复制，其结果必然是副本完全等同于本尊。reference复制的结果必然是两个reference指向同一块内存空间。<br />虽然在方法中对于副本的操作并不会影响到本尊，但对内存空间的修改确实实实在在的。<br />回到调用点，虽然本尊依然不知道曾经发生过的一切，但它按照原来的方式访问内存的时候，取到的确是经过方法修改之后的内容。<br />于是方法可以把自己的影响扩展到方法之外。<br />&nbsp;<br />多说几句<br />这个问题起源于我对C/C++中同样问题的思考。同C/C++相比，在changeReference中对reference赋值可能并不会造成什么很严重的后果，而在C/C++中，这么做却会造成臭名昭著的&#8220;内存泄漏&#8221;，根本的原因在于Java拥有了可爱的GC功能。即便这样，我仍不推荐使用这种的手法，毕竟GC已经很忙了，我们怎么好意思再麻烦人家。<br />在C/C++中，这个问题还可以继续引申。既然在函数中对于指针直接赋值行不通，那么如何在函数中修改指针呢？答案很简单，指针的指针，也就是把原来的指针看作一个普通的数据，把一个指向它的指针传到函数中就可以了。<br />同样的问题到了Java中就没有那么美妙的解决方案了，因为Java中可没有reference的reference这样的语法。可能的变通就是将reference进行封装成类。至于值不值，公道自在人心。</p><img src ="http://www.cppblog.com/chenglong7997/aggbug/170891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-04-11 13:30 <a href="http://www.cppblog.com/chenglong7997/articles/170891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> java中的多线程(转)</title><link>http://www.cppblog.com/chenglong7997/articles/169591.html</link><dc:creator>Snape</dc:creator><author>Snape</author><pubDate>Fri, 30 Mar 2012 19:19:00 GMT</pubDate><guid>http://www.cppblog.com/chenglong7997/articles/169591.html</guid><wfw:comment>http://www.cppblog.com/chenglong7997/comments/169591.html</wfw:comment><comments>http://www.cppblog.com/chenglong7997/articles/169591.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/chenglong7997/comments/commentRss/169591.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/chenglong7997/services/trackbacks/169591.html</trackback:ping><description><![CDATA[<div style="text-align: left; background-color: #d6d3d6; "><div>java中的多线程</div><div>在java中要想实现多线程，有两种手段，一种是继续Thread类，另外一种是实现Runable接口。</div><div>对于直接继承Thread的类来说，代码大致框架是：</div><div></div><div>class 类名 extends Thread{</div><div>方法1;</div><div>方法2；</div><div>&#8230;</div><div>public void run(){</div><div>// other code&#8230;</div><div>}</div><div>属性1；</div><div>属性2；</div><div>&#8230;</div><div>&nbsp;</div><div>}</div><div>先看一个简单的例子：</div><div>/**</div><div>&nbsp;* @author Rollen-Holt 继承Thread类,直接调用run方法</div><div>&nbsp;* */</div><div>class hello extends Thread {</div><div>&nbsp;</div><div>&nbsp; &nbsp; public hello() {</div><div>&nbsp;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public hello(String name) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 5; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(name + "运行 &nbsp; &nbsp; " + i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h1=new hello("A");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h2=new hello("B");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.run();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.run();</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private String name;</div><div>}</div><div>【运行结果】：</div><div>A运行 &nbsp; &nbsp; 0</div><div>A运行 &nbsp; &nbsp; 1</div><div>A运行 &nbsp; &nbsp; 2</div><div>A运行 &nbsp; &nbsp; 3</div><div>A运行 &nbsp; &nbsp; 4</div><div>B运行 &nbsp; &nbsp; 0</div><div>B运行 &nbsp; &nbsp; 1</div><div>B运行 &nbsp; &nbsp; 2</div><div>B运行 &nbsp; &nbsp; 3</div><div>B运行 &nbsp; &nbsp; 4</div><div>我们会发现这些都是顺序执行的，说明我们的调用方法不对，应该调用的是start（）方法。</div><div>当我们把上面的主函数修改为如下所示的时候：</div><div></div><div>public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h1=new hello("A");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h2=new hello("B");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; }</div><div>然后运行程序，输出的可能的结果如下：</div><div>A运行 &nbsp; &nbsp; 0</div><div>B运行 &nbsp; &nbsp; 0</div><div>B运行 &nbsp; &nbsp; 1</div><div>B运行 &nbsp; &nbsp; 2</div><div>B运行 &nbsp; &nbsp; 3</div><div>B运行 &nbsp; &nbsp; 4</div><div>A运行 &nbsp; &nbsp; 1</div><div>A运行 &nbsp; &nbsp; 2</div><div>A运行 &nbsp; &nbsp; 3</div><div>A运行 &nbsp; &nbsp; 4</div><div>因为需要用到CPU的资源，所以每次的运行结果基本是都不一样的，呵呵。</div><div>注意：虽然我们在这里调用的是start（）方法，但是实际上调用的还是run（）方法的主体。</div><div>那么：为什么我们不能直接调用run（）方法呢？</div><div>我的理解是：线程的运行需要本地操作系统的支持。</div><div>如果你查看start的源代码的时候，会发现：</div><div></div><div>public synchronized void start() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; /**</div><div>&nbsp; &nbsp; &nbsp;* This method is not invoked for the main method thread or "system"</div><div>&nbsp; &nbsp; &nbsp;* group threads created/set up by the VM. Any new functionality added&nbsp;</div><div>&nbsp; &nbsp; &nbsp;* to this method in the future may have to also be added to the VM.</div><div>&nbsp; &nbsp; &nbsp;*</div><div>&nbsp; &nbsp; &nbsp;* A zero status value corresponds to state "NEW".</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (threadStatus != 0 || this != me)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalThreadStateException();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; group.add(this);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; start0();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (stopBeforeStart) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; stop0(throwableFromStop);</div><div>&nbsp; &nbsp; }</div><div>}</div><div>private native void start0();</div><div>注意我用红色加粗的那一条语句，说明此处调用的是start0（）。并且这个这个方法用了native关键字，次关键字表示调用本地操作系统的函数。因为多线程的实现需要本地操作系统的支持。</div><div>但是start方法重复调用的话，会出现java.lang.IllegalThreadStateException异常。</div><div>通过实现Runnable接口：</div><div>&nbsp;</div><div>大致框架是：</div><div></div><div>class 类名 implements Runnable{</div><div>方法1;</div><div>方法2；</div><div>&#8230;</div><div>public void run(){</div><div>// other code&#8230;</div><div>}</div><div>属性1；</div><div>属性2；</div><div>&#8230;</div><div>&nbsp;</div><div>}</div><div>来先看一个小例子吧：</div><div></div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt 实现Runnable接口</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp;</div><div>&nbsp; &nbsp; public hello() {</div><div>&nbsp;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public hello(String name) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 5; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(name + "运行 &nbsp; &nbsp; " + i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h1=new hello("线程A");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread demo= new Thread(h1);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h2=new hello("线程Ｂ");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread demo1=new Thread(h2);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo1.start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private String name;</div><div>}</div><div>【可能的运行结果】：</div><div>线程A运行 &nbsp; &nbsp; 0</div><div>线程Ｂ运行 &nbsp; &nbsp; 0</div><div>线程Ｂ运行 &nbsp; &nbsp; 1</div><div>线程Ｂ运行 &nbsp; &nbsp; 2</div><div>线程Ｂ运行 &nbsp; &nbsp; 3</div><div>线程Ｂ运行 &nbsp; &nbsp; 4</div><div>线程A运行 &nbsp; &nbsp; 1</div><div>线程A运行 &nbsp; &nbsp; 2</div><div>线程A运行 &nbsp; &nbsp; 3</div><div>线程A运行 &nbsp; &nbsp; 4</div><div>&nbsp;</div><div>关于选择继承Thread还是实现Runnable接口？</div><div>其实Thread也是实现Runnable接口的：</div><div>?</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>class Thread implements Runnable {</div><div>&nbsp; &nbsp; //&#8230;</div><div>public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (target != null) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;target.run();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>}</div><div>其实Thread中的run方法调用的是Runnable接口的run方法。不知道大家发现没有，Thread和Runnable都实现了run方法，这种操作模式其实就是代理模式。关于代理模式，我曾经写过一个小例子呵呵，大家有兴趣的话可以看一下：http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html</div><div>Thread和Runnable的区别：</div><div>如果一个类继承Thread，则不适合资源共享。但是如果实现了Runable接口的话，则很容易的实现资源共享。</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt 继承Thread类，不能资源共享</div><div>&nbsp;* */</div><div>class hello extends Thread {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 7; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (count &gt; 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("count= " + count--);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h1 = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h2 = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello h3 = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private int count = 5;</div><div>}</div><div>【运行结果】：</div><div>count= 5</div><div>count= 4</div><div>count= 3</div><div>count= 2</div><div>count= 1</div><div>count= 5</div><div>count= 4</div><div>count= 3</div><div>count= 2</div><div>count= 1</div><div>count= 5</div><div>count= 4</div><div>count= 3</div><div>count= 2</div><div>count= 1</div><div>大家可以想象，如果这个是一个买票系统的话，如果count表示的是车票的数量的话，说明并没有实现资源的共享。</div><div>我们换为Runnable接口：</div><div>/**</div><div>&nbsp;* @author Rollen-Holt 继承Thread类，不能资源共享</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 7; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (count &gt; 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("count= " + count--);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he=new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(he).start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private int count = 5;</div><div>}</div><div>【运行结果】：</div><div>count= 5</div><div>count= 4</div><div>count= 3</div><div>count= 2</div><div>count= 1</div><div>&nbsp;</div><div>总结一下吧：</div><div>实现Runnable接口比继承Thread类所具有的优势：</div><div>1）：适合多个相同的程序代码的线程去处理同一个资源</div><div>2）：可以避免java中的单继承的限制</div><div>3）：增加程序的健壮性，代码可以被多个线程共享，代码和数据独立。</div><div>所以，本人建议大家劲量实现接口。</div><div>/**</div><div>&nbsp;* @author Rollen-Holt&nbsp;</div><div>&nbsp;* 取得线程的名称</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 3; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(he,"A").start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(he,"B").start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(he).start();</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：</div><div>A</div><div>A</div><div>A</div><div>B</div><div>B</div><div>B</div><div>Thread-0</div><div>Thread-0</div><div>Thread-0</div><div>说明如果我们没有指定名字的话，系统自动提供名字。</div><div>提醒一下大家：main方法其实也是一个线程。在java中所以的线程都是同时启动的，至于什么时候，哪个先执行，完全看谁先得到CPU的资源。</div><div>&nbsp;</div><div>在java中，每次程序运行至少启动2个线程。一个是main线程，一个是垃圾收集线程。因为每当使用java命令执行一个类的时候，实际上都会启动一个ＪＶＭ，每一个ｊＶＭ实习在就是在操作系统中启动了一个进程。</div><div>判断线程是否启动</div><div>/**</div><div>&nbsp;* @author Rollen-Holt 判断线程是否启动</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 3; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread demo = new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("线程启动之前---》" + demo.isAlive());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("线程启动之后---》" + demo.isAlive());</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】</div><div>线程启动之前---》false</div><div>线程启动之后---》true</div><div>Thread-0</div><div>Thread-0</div><div>Thread-0</div><div>主线程也有可能在子线程结束之前结束。并且子线程不受影响，不会因为主线程的结束而结束。</div><div>&nbsp;</div><div>线程的强制执行：</div><div></div><div>/**</div><div>&nbsp; &nbsp; &nbsp;* @author Rollen-Holt 线程的强制执行</div><div>&nbsp; &nbsp; &nbsp;* */</div><div>&nbsp; &nbsp; class hello implements Runnable {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 3; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread demo = new Thread(he,"线程");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; demo.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;50;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(i&gt;10){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; demo.join(); &nbsp;//强制执行demo</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("main 线程执行--&gt;"+i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>【运行的结果】：</div><div>main 线程执行--&gt;0</div><div>main 线程执行--&gt;1</div><div>main 线程执行--&gt;2</div><div>main 线程执行--&gt;3</div><div>main 线程执行--&gt;4</div><div>main 线程执行--&gt;5</div><div>main 线程执行--&gt;6</div><div>main 线程执行--&gt;7</div><div>main 线程执行--&gt;8</div><div>main 线程执行--&gt;9</div><div>main 线程执行--&gt;10</div><div>线程</div><div>线程</div><div>线程</div><div>main 线程执行--&gt;11</div><div>main 线程执行--&gt;12</div><div>main 线程执行--&gt;13</div><div>．．．</div><div>&nbsp;</div><div>线程的休眠：</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt 线程的休眠</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 3; i++) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(2000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName() + i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread demo = new Thread(he, "线程");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo.start();</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：（结果每隔2s输出一个）</div><div>线程0</div><div>线程1</div><div>线程2</div><div>&nbsp;</div><div>线程的中断：</div><div>/**</div><div>&nbsp;* @author Rollen-Holt 线程的中断</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("执行run方法");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(10000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("线程完成休眠");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("休眠被打断");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; &nbsp;//返回到程序的调用处</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("线程正常终止");</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread demo = new Thread(he, "线程");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(2000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; demo.interrupt(); //2s后中断线程</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：</div><div>执行run方法</div><div>休眠被打断</div><div>&nbsp;</div><div>在java程序中，只要前台有一个线程在运行，整个java程序进程不会小时，所以此时可以设置一个后台线程，这样即使java进程小时了，此后台线程依然能够继续运行。</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt 线程的优先级</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;5;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName()+"运行"+i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h1=new Thread(new hello(),"A");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h2=new Thread(new hello(),"B");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h3=new Thread(new hello(),"C");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.setPriority(8);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.setPriority(2);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.setPriority(6);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：</div><div>A运行0</div><div>A运行1</div><div>A运行2</div><div>A运行3</div><div>A运行4</div><div>B运行0</div><div>C运行0</div><div>C运行1</div><div>C运行2</div><div>C运行3</div><div>C运行4</div><div>B运行1</div><div>B运行2</div><div>B运行3</div><div>B运行4</div><div>。但是请读者不要误以为优先级越高就先执行。谁先执行还是取决于谁先去的CPU的资源、</div><div>&nbsp;</div><div>另外，主线程的优先级是5.</div><div>线程的礼让。</div><div>在线程操作中，也可以使用yield（）方法，将一个线程的操作暂时交给其他线程执行。</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt 线程的优先级</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;5;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName()+"运行"+i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(i==3){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("线程的礼让");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.currentThread().yield();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h1=new Thread(new hello(),"A");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h2=new Thread(new hello(),"B");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; }</div><div>}</div><div>A运行0</div><div>A运行1</div><div>A运行2</div><div>A运行3</div><div>线程的礼让</div><div>A运行4</div><div>B运行0</div><div>B运行1</div><div>B运行2</div><div>B运行3</div><div>线程的礼让</div><div>B运行4</div><div>&nbsp;</div><div>&nbsp;</div><div>同步和死锁：</div><div>【问题引出】:比如说对于买票系统，有下面的代码：</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt&nbsp;</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;10;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(count&gt;0){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(1000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch(InterruptedException e){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(count--);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he=new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h1=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h2=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h3=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; private int count=5;</div><div>}</div><div>【运行结果】：</div><div>5</div><div>4</div><div>3</div><div>2</div><div>1</div><div>0</div><div>-1</div><div>这里出现了-1，显然这个是错的。，应该票数不能为负值。</div><div>如果想解决这种问题，就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行，</div><div>其他的线程必须等到这个线程结束之后才能继续执行。</div><div>【使用线程同步解决问题】</div><div>采用同步的话，可以使用同步代码块和同步方法两种来完成。</div><div>&nbsp;</div><div>【同步代码块】：</div><div>语法格式：</div><div>synchronized（同步对象）{</div><div>&nbsp;//需要同步的代码</div><div>}</div><div>但是一般都把当前对象this作为同步对象。</div><div>比如对于上面的买票的问题，如下：</div><div></div><div>/**</div><div>&nbsp;* @author Rollen-Holt&nbsp;</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;10;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized (this) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(count&gt;0){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(1000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch(InterruptedException e){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(count--);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he=new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h1=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h2=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h3=new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; private int count=5;</div><div>}</div><div>【运行结果】：（每一秒输出一个结果）</div><div>5</div><div>4</div><div>3</div><div>2</div><div>1</div><div>【同步方法】</div><div>也可以采用同步方法。</div><div>语法格式为synchronized 方法返回类型 方法名（参数列表）{</div><div>&nbsp; &nbsp; // 其他代码</div><div>}</div><div>现在，我们采用同步方法解决上面的问题。</div><div>?</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div><div>10</div><div>11</div><div>12</div><div>13</div><div>14</div><div>15</div><div>16</div><div>17</div><div>18</div><div>19</div><div>20</div><div>21</div><div>22</div><div>23</div><div>24</div><div>25</div><div>26</div><div>27</div><div>28</div><div>29</div><div>30</div><div>31</div><div>32</div><div>33</div><div>/**</div><div>&nbsp;* @author Rollen-Holt</div><div>&nbsp;* */</div><div>class hello implements Runnable {</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 10; ++i) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sale();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public synchronized void sale() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (count &gt; 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(1000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (InterruptedException e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(count--);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; hello he = new hello();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h1 = new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h2 = new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Thread h3 = new Thread(he);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h1.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h2.start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; h3.start();</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private int count = 5;</div><div>}</div><div>【运行结果】（每秒输出一个）</div><div>5</div><div>4</div><div>3</div><div>2</div><div>1</div><div>提醒一下，当多个线程共享一个资源的时候需要进行同步，但是过多的同步可能导致死锁。</div><div>此处列举经典的生产者和消费者问题。</div><div>【生产者和消费者问题】</div><div>先看一段有问题的代码。</div><div>class Info {</div><div>&nbsp;</div><div>&nbsp; &nbsp; public String getName() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setName(String name) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public int getAge() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setAge(int age) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.age = age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; private String name = "Rollen";</div><div>&nbsp; &nbsp; private int age = 20;</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 生产者</div><div>&nbsp;* */</div><div>class Producer implements Runnable{</div><div>&nbsp; &nbsp; private Info info=null;</div><div>&nbsp; &nbsp; Producer(Info info){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info=info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public void run(){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean flag=false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;25;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(flag){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.setName("Rollen");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.setAge(20);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag=false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.setName("chunGe");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.setAge(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag=true;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>/**</div><div>&nbsp;* 消费者类</div><div>&nbsp;* */</div><div>class Consumer implements Runnable{</div><div>&nbsp; &nbsp; private Info info=null;</div><div>&nbsp; &nbsp; public Consumer(Info info){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info=info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public void run(){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0;i&lt;25;++i){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(this.info.getName()+"&lt;----&gt;"+this.info.getAge());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 测试类</div><div>&nbsp;* */</div><div>class hello{</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Info info=new Info();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Producer pro=new Producer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Consumer con=new Consumer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(pro).start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(con).start();</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>chunGe&lt;----&gt;100</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>Rollen&lt;----&gt;100</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>chunGe&lt;----&gt;20</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>Rollen&lt;----&gt;100</div><div>chunGe&lt;----&gt;20</div><div>大家可以从结果中看到，名字和年龄并没有对于。</div><div>&nbsp;</div><div>那么如何解决呢？</div><div>1） 加入同步</div><div>2） 加入等待和唤醒</div><div>先来看看加入同步会是如何。</div><div>class Info {</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public String getName() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setName(String name) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public int getAge() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setAge(int age) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.age = age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public synchronized void set(String name, int age){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name=name;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.age=age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public synchronized void get(){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(this.getName()+"&lt;===&gt;"+this.getAge());</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; private String name = "Rollen";</div><div>&nbsp; &nbsp; private int age = 20;</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 生产者</div><div>&nbsp;* */</div><div>class Producer implements Runnable {</div><div>&nbsp; &nbsp; private Info info = null;</div><div>&nbsp;</div><div>&nbsp; &nbsp; Producer(Info info) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info = info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean flag = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 25; ++i) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (flag) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.set("Rollen", 20);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.set("ChunGe", 100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag = true;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 消费者类</div><div>&nbsp;* */</div><div>class Consumer implements Runnable {</div><div>&nbsp; &nbsp; private Info info = null;</div><div>&nbsp;</div><div>&nbsp; &nbsp; public Consumer(Info info) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info = info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 25; ++i) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.get();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 测试类</div><div>&nbsp;* */</div><div>class hello {</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Info info = new Info();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Producer pro = new Producer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Consumer con = new Consumer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(pro).start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(con).start();</div><div>&nbsp; &nbsp; }</div><div>}</div><div>【运行结果】：</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>ChunGe&lt;===&gt;100</div><div>从运行结果来看，错乱的问题解决了，现在是Rollen 对应20，ChunGe对于100</div><div>，但是还是出现了重复读取的问题，也肯定有重复覆盖的问题。如果想解决这个问题，就需要使用Object类帮忙了、</div><div>，我们可以使用其中的等待和唤醒操作。</div><div>要完成上面的功能，我们只需要修改Info类饥渴，在其中加上标志位，并且通过判断标志位完成等待和唤醒的操作，代码如下：</div><div></div><div>class Info {</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public String getName() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setName(String name) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public int getAge() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void setAge(int age) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.age = age;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public synchronized void set(String name, int age){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if(!flag){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super.wait();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.name=name;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.age=age;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; flag=false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; super.notify();</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; public synchronized void get(){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if(flag){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super.wait();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(this.getName()+"&lt;===&gt;"+this.getAge());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; flag=true;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; super.notify();</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; private String name = "Rollen";</div><div>&nbsp; &nbsp; private int age = 20;</div><div>&nbsp; &nbsp; private boolean flag=false;</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 生产者</div><div>&nbsp;* */</div><div>class Producer implements Runnable {</div><div>&nbsp; &nbsp; private Info info = null;</div><div>&nbsp;</div><div>&nbsp; &nbsp; Producer(Info info) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info = info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean flag = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 25; ++i) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (flag) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.set("Rollen", 20);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.set("ChunGe", 100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flag = true;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 消费者类</div><div>&nbsp;* */</div><div>class Consumer implements Runnable {</div><div>&nbsp; &nbsp; private Info info = null;</div><div>&nbsp;</div><div>&nbsp; &nbsp; public Consumer(Info info) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.info = info;</div><div>&nbsp; &nbsp; }</div><div>&nbsp;</div><div>&nbsp; &nbsp; public void run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; 25; ++i) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.info.get();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>&nbsp;</div><div>/**</div><div>&nbsp;* 测试类</div><div>&nbsp;* */</div><div>class hello {</div><div>&nbsp; &nbsp; public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Info info = new Info();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Producer pro = new Producer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Consumer con = new Consumer(info);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(pro).start();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; new Thread(con).start();</div><div>&nbsp; &nbsp; }</div><div>}</div><div></div><div>【程序运行结果】：</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>ChunGe&lt;===&gt;100</div><div>Rollen&lt;===&gt;20</div><div>先在看结果就可以知道，之前的问题完全解决。</div><div style="color: #333333; font-family: Verdana, Arial, sans-serif, 'Lucida Grande'; "></div></div><img src ="http://www.cppblog.com/chenglong7997/aggbug/169591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/chenglong7997/" target="_blank">Snape</a> 2012-03-31 03:19 <a href="http://www.cppblog.com/chenglong7997/articles/169591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>