2.看TreeMap源码的deleteEntry方法遇到的问题
问题场景
在看TreeMap类是如何删除红黑树时,从remove方法看起,当看到deleteEntry(Entry<K,V> p)方法时:
就是图中标红的三行代码:
p.key = s.key;
p.value = s.value;
p = s;
将后继节点的键赋值给待删除节点的键、将后继节点的值赋值给待删除节点的值、将p指向后继节点。
我的疑惑
已经将键和值都赋值给待删除的替换节点p了,为什么将p指向s?在这里我我错误的以为p节点指向s节点后,待删除节点的位置就变成s了。其实我这种理解完全错误。
解决方案
我产生这样的疑惑,是因为我没有完全理解变量、对象、方法区域;栈、堆之间的关系。在我经过几个小时的小纠结后,我得出的结论如下,用一张图直观的表示出来:
p是变量,存储在栈中,而通过new创建出来的对象存储在堆中;栈中的变量通过指针指向堆中的对象。p.key = s.key语句将栈中变量指向的对象的key值变成栈中s变量所指向的对象的key值;p.value = s.value语句将栈中p变量所指向的对象的value值变成栈中s变量所指向的对象的value值;之后将栈中p变量指向s所指向的对象。这个解释算是很标准了。
如果将这个问题放在红黑树中,p为树中一个待删除节点,s为p的后继节点。使用s的key、value值替换p的key和value值,在将p指向s,如果以p为中心的理解,很难理解,是个错误的方向。正确的理解方式:使用栈中s变量所指向的对象的key值和value值赋值给栈中p变量所指向的key值和value值,p所指向的对象是树中要删除被替换掉的节点,使用后继节点替换掉,赋值操作是指上就是在替换节点,而其父节点、左右子树都不用在重新赋值;之后再将栈中p变量指向堆中s之前所指向的对象。p之前所指向的对象在内存的堆中依旧存在,只是不能通过p直接访问了而已。
在这里要总结一点:java中的变量只是堆中对象的引用,而不是真实的对象本身。变量只是一个对象的引用、变量只是一个对象的引用、变量只是一个对象的引用(重要的事说三遍)。