|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
不得不提一下的是:.net是看到java红,而开发出来的工具。
起首检察上面一段代码,我指出了成绩代码的地点,读者先本人思索一下这段代码会有甚么成绩。
这是用clone办法完全拷贝一个二项堆(BinomialHeap)布局的代码。二项堆中包括一个外部类BinomialHeapEntry,这个外部类的对象即二项堆中的每个结点,除包括结点对应的关头字外,还纪录父节点parent,下一个兄弟结点sibling和第一个孩子结点child三个指针。二项堆的根表经由过程每棵二项树根节点的sibling指针链接。
cloneBinomialTree(BinomialHeapEntryroot)办法递回拷贝一个根节点(含根节点)下的全部二项树,clone办法中遍历根表中每一个树根结点,拷贝对应的二项树,然后将新的head指针赋给拷贝后的新堆。- publicclassBinomialHeap<E>implementsCloneable{
- transientBinomialHeapEntryhead;//根表中的第一个元素
- intsize;//全部二项堆的巨细(结点数)
- privateclassBinomialHeapEntry{
- Eelement;
- transientBinomialHeapEntryparent=null,child=null,
- sibling=null;
- transientintdegree=0;
- privateBinomialHeapEntry(Eelement){
- this.element=element;
- }
- //取得孩子结点的迭代器
- privateIterable<BinomialHeapEntry>children{...}
- }
- @Override
- publicBinomialHeap<E>clone(){
- //TODOAuto-generatedmethodstub
- BinomialHeap<E>clone;
- try{
- clone=(BinomialHeap<E>)super.clone();
- }catch(CloneNotSupportedExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- thrownewInternalError();
- }
- BinomialHeapEntrynewHead=null,curRoot=null;
- //遍历根表
- Iterator<HeapEntry<E>>rootIt=this.roots().iterator();
- while(rootIt.hasNext()){
- BinomialHeapEntryroot=(BinomialHeapEntry)rootIt.next();
- //拷贝根节点下的整棵二项树<br><spanstyle="color:#ff0000;">//BUG引进的中央</span>
- BinomialHeapEntrynewRoot=cloneBinomialTree(root);
- if(curRoot==null){
- newHead=newRoot;
- }else{
- curRoot.sibling=newRoot;
- }
- curRoot=newRoot;
- }
- clone.head=newHead;
- returnclone;
- }
- //拷贝根节点(含根节点)下的整棵子树
- privateBinomialHeapEntrycloneBinomialTree(BinomialHeapEntryroot){
- BinomialHeapEntrynewRoot=newBinomialHeapEntry(root.element());
- BinomialHeapEntrycurChild=null;
- //遍历根节点的一切孩子结点
- Iterator<HeapEntry<E>>childIt=root.children().iterator();
- while(childIt.hasNext()){
- BinomialHeapEntrychild=(BinomialHeapEntry)childIt.next();
- //递回拷贝孩子节点下的子树
- BinomialHeapEntrynewChild=cloneBinomialTree(child);
- newChild.parent=newRoot;
- if(curChild==null){
- newRoot.child=newChild;
- }else{
- curChild.sibling=newChild;
- }
- curChild=newChild;
- }
- newRoot.degree=root.degree;
- returnnewRoot;
- }
- }
复制代码 先回忆一下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++基本一致,但是启动速度还是慢.代码安全,但容易性能陷阱. |
|