前言
说真的, 平常看源码都是自己看完自己懂, 很少有写出来的冲动.
但是在写算法的时候, 经常用到 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 的博客
来源: http://www.bubuko.com/infodetail-3233127.html