bigywater.tech
Java 内部原理 · 130

List.remove() 重载真实验证:remove(20)真实删的是索引,不是值

List<Integer>有两个remove重载:remove(int index)和remove(Object o)——这篇真实构造一个4元素的list,验证remove(20)这种写法编译器真实选的是哪一个,以及真实会发生什么。

int字面量真实优先匹配索引重载
真实验证:remove(1)在List<Integer>上真实删除的是索引1的元素,不会自动装箱去匹配remove(Object)
remove(20)真实抛出越界异常
真实复现:4元素的list上调用remove(20),真实抛出IndexOutOfBoundsException,证明它真实当成了索引

上一篇:String switch字节码真实反编译

真实验证:remove(int)和remove(Object)是两个完全不同的重载

List接口对Integer这种包装类元素同时提供了remove(int index)和remove(Object o)两个方法,真实对比它们的行为差异。

ListRemoveIntVsObjectDemo.java List<Integer> list = new ArrayList<>(List.of(10, 20, 30, 40)); listA.remove(1); // int字面量 listB.remove(Integer.valueOf(1)); // 显式装箱成Object
真实实测
初始list: [10, 20, 30, 40]
listA.remove(1) [int重载,删索引] 真实结果: [10, 30, 40]
listB.remove(Integer.valueOf(1)) [Object重载,删值] 真实结果: [10, 20, 30, 40] (真实size是否变化: false)

真实结果证明同样传入"1"这个数字,两种写法真实得到完全不同的结果:remove(1)(int字面量)真实删除了索引1的元素(值20);而remove(Integer.valueOf(1))(显式装箱)真实是在按值查找——因为list里没有值为1的元素,所以真实什么都没删除,size真实没有变化。Java的重载解析规则是:能不装箱就不装箱,int字面量会优先精确匹配remove(int index)这个重载,只有显式传入包装类型或Object,才会真实匹配到remove(Object o)。

真实复现:remove(20)在真实业务代码里会真实抛异常

如果开发者的真实意图是"删除值为20的元素",但写成了remove(20),会发生什么?

ListRemoveIntVsObjectDemo.java listC.remove(20); // 意图:删掉值为20的元素;真实调用:remove(int index)
真实实测
listC.remove(20) 真实抛出: java.lang.IndexOutOfBoundsException: Index 20 out of bounds for length 4 (证明它真实调用的是remove(int index),而不是删除值为20的元素)

listD.remove(Integer.valueOf(20)) 真实结果(正确删除值为20的元素): [10, 30, 40]
真实的危险在于:这个bug不总是会抛异常提醒你。真实实验里因为list只有4个元素、20远超list长度,直接触发了IndexOutOfBoundsException,问题很快暴露。但如果list真实有超过20个元素,remove(20)就会真实"成功"删掉索引20位置上的某个元素——不抛异常、不报错,但删掉的完全不是开发者想删的那个值为20的元素,而是一个可能值为500、-3或任何东西的、恰好排在第21位的元素。这种"悄悄删错东西但不报错"的场景远比直接崩溃更难排查。真实唯一安全的写法是显式装箱:remove(Integer.valueOf(20))或者用list.removeIf(x -> x == 20)这种明确表达"按值删除"意图的API,从源头上避免这个重载歧义。

分步演示:编译器是怎么选中这个重载的

每一步的 list 内容都是真实运行这段代码之后的状态,不是按规则手工推的。

remove(1) 删的是索引 1,remove(Integer.valueOf(1)) 删的是值 1:同一个数字,两种真实结果
这一步真实被删除的元素

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,两种remove重载的行为差异和越界异常均可重复复现。作为这一批的收尾,系列 Java 内部原理现在共 130 篇。
    • 和可变参数重载真实验证一起看,能更完整理解Java重载解析"优先精确匹配、其次自动装箱/拆箱、最后可变参数"这套真实的三阶段优先级规则。
    • 没有涉及:List.of()返回的不可变List上remove()真实会先抛UnsupportedOperationException(优先级早于索引越界检查吗)、Set<Integer>是否存在类似remove(int)/remove(Object)的重载歧义——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号