仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 497|回复: 8
打印 上一主题 下一主题

[学习教程] 了解下JAVA的Java外部类this$0字段发生的一个小bug

[复制链接]
蒙在股里 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-18 11:00:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
不得不提一下的是:.net是看到java红,而开发出来的工具。
起首检察上面一段代码,我指出了成绩代码的地点,读者先本人思索一下这段代码会有甚么成绩。
这是用clone办法完全拷贝一个二项堆(BinomialHeap)布局的代码。二项堆中包括一个外部类BinomialHeapEntry,这个外部类的对象即二项堆中的每个结点,除包括结点对应的关头字外,还纪录父节点parent,下一个兄弟结点sibling和第一个孩子结点child三个指针。二项堆的根表经由过程每棵二项树根节点的sibling指针链接。
cloneBinomialTree(BinomialHeapEntryroot)办法递回拷贝一个根节点(含根节点)下的全部二项树,clone办法中遍历根表中每一个树根结点,拷贝对应的二项树,然后将新的head指针赋给拷贝后的新堆。
  1. publicclassBinomialHeap<E>implementsCloneable{
  2. transientBinomialHeapEntryhead;//根表中的第一个元素
  3. intsize;//全部二项堆的巨细(结点数)
  4. privateclassBinomialHeapEntry{
  5. Eelement;
  6. transientBinomialHeapEntryparent=null,child=null,
  7. sibling=null;
  8. transientintdegree=0;
  9. privateBinomialHeapEntry(Eelement){
  10. this.element=element;
  11. }
  12. //取得孩子结点的迭代器
  13. privateIterable<BinomialHeapEntry>children{...}
  14. }
  15. @Override
  16. publicBinomialHeap<E>clone(){
  17. //TODOAuto-generatedmethodstub
  18. BinomialHeap<E>clone;
  19. try{
  20. clone=(BinomialHeap<E>)super.clone();
  21. }catch(CloneNotSupportedExceptione){
  22. //TODOAuto-generatedcatchblock
  23. e.printStackTrace();
  24. thrownewInternalError();
  25. }
  26. BinomialHeapEntrynewHead=null,curRoot=null;
  27. //遍历根表
  28. Iterator<HeapEntry<E>>rootIt=this.roots().iterator();
  29. while(rootIt.hasNext()){
  30. BinomialHeapEntryroot=(BinomialHeapEntry)rootIt.next();
  31. //拷贝根节点下的整棵二项树<br><spanstyle="color:#ff0000;">//BUG引进的中央</span>
  32. BinomialHeapEntrynewRoot=cloneBinomialTree(root);
  33. if(curRoot==null){
  34. newHead=newRoot;
  35. }else{
  36. curRoot.sibling=newRoot;
  37. }
  38. curRoot=newRoot;
  39. }
  40. clone.head=newHead;
  41. returnclone;
  42. }
  43. //拷贝根节点(含根节点)下的整棵子树
  44. privateBinomialHeapEntrycloneBinomialTree(BinomialHeapEntryroot){
  45. BinomialHeapEntrynewRoot=newBinomialHeapEntry(root.element());
  46. BinomialHeapEntrycurChild=null;
  47. //遍历根节点的一切孩子结点
  48. Iterator<HeapEntry<E>>childIt=root.children().iterator();
  49. while(childIt.hasNext()){
  50. BinomialHeapEntrychild=(BinomialHeapEntry)childIt.next();
  51. //递回拷贝孩子节点下的子树
  52. BinomialHeapEntrynewChild=cloneBinomialTree(child);
  53. newChild.parent=newRoot;
  54. if(curChild==null){
  55. newRoot.child=newChild;
  56. }else{
  57. curChild.sibling=newChild;
  58. }
  59. curChild=newChild;
  60. }
  61. newRoot.degree=root.degree;
  62. returnnewRoot;
  63. }
  64. }
复制代码
先回忆一下Java外部类的一些常识,非静态的Java外部类作为内部类的一个成员,只能经由过程内部类的对象来会见,要创立一个外部类对象,也必要经由过程内部类对象来创立,即:outerObject.newInnerClass()。这时候,所创立的外部类对象会发生称号为this$0的一个字段,该字段保留的是创立这个外部类对象的内部类对象援用,即方才的outerObject。这个援用使得一个外部类对象能够自在的会见内部类的成员变量。
在回忆下面二项堆拷贝的代码,在挪用cloneBinomialTree办法拷贝二项树时,我们试图经由过程newBinomialHeapEntry()来创立一个新的结点,把新的结点作为新二项堆中的结点,但现实上我们实践挪用的是this.newBinomialHeapEntry(),也就是说创立的新结点中,this$0是指向老的二项堆(this)而不是新的正在拷贝的二项堆(clone)。这使得我们失掉拷贝的新二项堆以后,经由过程新二项堆的任一结点会见和修正全部堆的信息时,修正的都是老的二项堆,最初发生了一系列奇异的了局。
要想修复这个bug很复杂,把clone办法中的BinomialHeapEntrynewRoot=cloneBinomialTree(root)即白色正文下的语句,修正为BinomialHeapEntrynewRoot=clone.cloneBinomialTree(root)。如许cloneBinomialTree办法中创立的结点都是经由过程clone对象创立,成绩也就办理了。
成绩实在对照复杂,这的确是今后在编程中值得注重的一点:拷贝外部类对象时思索分明拷贝后的对象this$0字段是不是指向的是你但愿指向的内部类对象。
检察本栏目更多出色内容:http://www.bianceng.cn/Programming/Java/

C#跟java类似,但是在跨平台方面理论上可以跨平台,实际上应用不大,执行性能优于java,跟C++基本一致,但是启动速度还是慢.代码安全,但容易性能陷阱.
冷月葬花魂 该用户已被删除
沙发
发表于 2015-1-20 12:32:05 | 只看该作者
在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。
莫相离 该用户已被删除
板凳
发表于 2015-1-29 06:41:04 | 只看该作者
关于设计模式的资料,还是向大家推荐banq的网站 [url]http://www.jdon.com/[/url],他把GOF的23种模式以通俗易懂的方式诠释出来,纯Java描述,真是经典中的经典。
若天明 该用户已被删除
地板
发表于 2015-2-5 21:42:47 | 只看该作者
我大二,Java也只学了一年,觉得还是看thinking in java好,有能力的话看英文原版(中文版翻的不怎么好),还能提高英文文档阅读能力。
兰色精灵 该用户已被删除
5#
发表于 2015-2-13 15:30:17 | 只看该作者
还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。
海妖 该用户已被删除
6#
发表于 2015-3-3 23:06:40 | 只看该作者
Java自面世后就非常流行,发展迅速,对C++语言形成了有力冲击。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台
变相怪杰 该用户已被删除
7#
发表于 2015-3-11 13:53:07 | 只看该作者
你就该学一学Servlet了。Servlet就是服务器端小程序,他负责生成发送给客户端的HTML文件。JSP在执行时,也是先转换成Servlet再运行的。虽说JSP理论上可以完全取代Servlet,这也是SUN推出JSP的本意,可是Servlet用来控制流程跳转还是挺方便的,也令程序更清晰。接下来你应该学习一下Javabean了,可能你早就看不管JSP在HTML中嵌Java代码的混乱方式了,这种方式跟ASP又有什么区别呢?
若相依 该用户已被删除
8#
发表于 2015-3-18 15:47:57 | 只看该作者
你快去找一份Java的编程工作来做吧(如果是在校学生可以去做兼职啊),在实践中提高自己,那才是最快的。不过你得祈祷在公司里碰到一个高手,而且他 还愿意不厌其烦地教你,这样好象有点难哦!还有一个办法就是读开放源码的程序了。我们知道开放源码大都出自高手,他们设计合理,考虑周到,再加上有广大的程序员参与,代码的价值自然是字字珠叽,铿锵有力(对不起,偶最近《金装四大才子》看多了)。
小妖女 该用户已被删除
9#
发表于 2015-3-26 02:39:01 | 只看该作者
我大二,Java也只学了一年,觉得还是看thinking in java好,有能力的话看英文原版(中文版翻的不怎么好),还能提高英文文档阅读能力。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-11-15 13:42

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表