1. 程式人生 > >2.看TreeMap原始碼的deleteEntry方法遇到的問題

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中的變數只是堆中物件的引用,而不是真實的物件本身。變數只是一個物件的引用、變數只是一個物件的引用、變數只是一個物件的引用(重要的事說三遍)。