2.看TreeMap源码的deleteEntry方法遇到的问题

本文深入探讨了Java中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中的变量只是堆中对象的引用,而不是真实的对象本身。变量只是一个对象的引用、变量只是一个对象的引用、变量只是一个对象的引用(重要的事说三遍)。

 

提供的参考引用未涉及解决 `cn.afterturn.easypoi.excel.imports.ExcelImportService.importExcel` 方法中出现 `java.util.NoSuchElementException` 异常(`TreeMap$PrivateEntryIterator.nextEntry` 和 `TreeMap$ValueIterator.next` 位置)的相关内容。不过,通常 `java.util.NoSuchElementException` 异常在使用迭代器时,当没有更多元素却调用了 `next()` 方法会抛出。以下是一些可能的解决方案: ### 检查数据源 确保导入的 Excel 文件格式正确,没有缺失必要的数据。文件可能存在空行、空列或者数据不完整的情况,这可能导致迭代器在遍历数据时出现异常。可以手动检查 Excel 文件,或者编写代码在导入前对文件进行验证。 ### 检查迭代逻辑 查看 `ExcelImportService.importExcel` 方法内部的迭代逻辑,确认是否存在提前结束迭代或者错误调用 `next()` 方法的情况。可能需要调试代码,跟踪迭代器的状态,确保在调用 `next()` 方法之前先调用 `hasNext()` 方法进行检查。 ### 示例代码检查迭代逻辑 ```java import java.util.Iterator; import java.util.TreeMap; public class IteratorCheckExample { public static void main(String[] args) { TreeMap<String, Integer> treeMap = new TreeMap<>(); treeMap.put("key1", 1); treeMap.put("key2", 2); Iterator<Integer> iterator = treeMap.values().iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); System.out.println(value); } } } ``` ### 检查依赖版本 确保使用的 `easypoi` 及其相关依赖的版本兼容。不兼容的版本可能会导致一些方法的行为不符合预期,从而引发异常。可以尝试更新或者回退相关依赖的版本。 ### 调试和日志记录 在关键位置添加日志记录,输出迭代器的状态和相关数据,帮助定位问题。例如,在调用 `next()` 方法前后输出 `hasNext()` 的结果,以及当前元素的值。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值