JAVA的List接口的remove重载方法调用原理

29次阅读

共计 1880 个字符,预计需要花费 5 分钟才能阅读完成。

前言

说真的,平常看源码都是自己看完自己懂,很少有写出来的冲动。
但是在写算法的时候,经常用到 java 中各种集合,其中也比较常用到 remove 方法。
remove 有重载函数,分别传入参数是索引 index 或者数据 Object(指定泛型后自动转换),如果指定泛型是其他数据类型还好,但是指定的是 Integer 或者是 int 的话,或者就有点懵了。
这曾经也困惑过我,所以我就唯有用实践解惑了。

测试类设计

  • 测试类一
public class Text {public void remove(int index){System.out.println("调用传参为 int 的 remove 方法");
    }

    public void remove(Integer object){System.out.println("调用传参为 Integer 的 remove 方法");
    }

    public void remove(Object object){System.out.println("调用传参为 Object 的 remove 方法");
    }
}
  • 测试类二
public class Text {public void remove(Integer object){System.out.println("调用传参为 Integer 的 remove 方法");
    }

    public void remove(Object object){System.out.println("调用传参为 Object 的 remove 方法");
    }
}
  • 测试类三
public class Text {public void remove(Object object){System.out.println("调用传参为 Object 的 remove 方法");
    }
}

结果

三个测试类分别传入 int,Integer,Object 型变量,观察效果。

  • 测试类一

传入类型为 int:调用传参为 int 的 remove 方法
传入类型为 Integer:调用传参为 Integer 的 remove 方法
传入类型为 Object:调用传参为 Object 的 remove 方法

  • 测试类二

传入类型为 int:调用传参为 Integer 的 remove 方法
传入类型为 Integer:调用传参为 Integer 的 remove 方法
传入类型为 Object:调用传参为 Object 的 remove 方法

  • 测试类三

传入类型为 int:调用传参为 Object 的 remove 方法
传入类型为 Integer:调用传参为 Object 的 remove 方法
传入类型为 Object:调用传参为 Object 的 remove 方法

从输出结果可以看出,当方法的传参的类层级逐渐变高时,层级较低的传参会进行向上转型适应传参的需要。

原因分析

下面我们先反编译各测试类的源码,结果如下

  • 测试类一

invokevirtual #11 // Method remove:(I)V

invokevirtual #15 // Method remove:(Ljava/lang/Integer;)V

invokevirtual #18 // Method remove:(Ljava/lang/Object;)V

  • 测试类二

invokevirtual #11 // Method remove:(Ljava/lang/Integer;)V

invokevirtual #11 // Method remove:(Ljava/lang/Integer;)V

invokevirtual #17 // Method remove:(Ljava/lang/Object;)V

  • 测试类三

invokevirtual #10 // Method remove:(Ljava/lang/Object;)V

invokevirtual #10 // Method remove:(Ljava/lang/Object;)V

invokevirtual #10 // Method remove:(Ljava/lang/Object;)V

可以看出,反编译代码中都是调用实例方法的命令,所以结果中自动 ” 向上转型 ” 其实是 jvm 的功劳。jvm 通过在编译时确定调用的传参类型,静态分派到具体方法的。
所以在前言中的困惑已经解除了,就是由于 jvm 中静态分派的实现,调用次序是 int->Integer->Object。

后记

也没什么想说的,感觉在阅读源码的时候必须多想想为什么这样做,为什么要这样实现,同时通过断点或者反编译的手段找出自己的答案。keep going!

本文首发于 cartoon 的博客
转载请注明出处:https://cartoonyu.github.io/cartoon-blog/post/java/java 的 list 接口的 remove 重载方法调用原理 /

正文完
 0