ArrayList的get()方法为什么可以直接将Object数组返回成泛型里的类型?

作者站长头像
站长
· 阅读数 18

ArrayList的get()方法为什么可以直接将Object数组返回成泛型里的T?今天阅读ArrayList源码时,为什么可以直接在返回类型为泛型的方法里直接返回Object数组,而我自己定义的类里却需要强转?以下是ArrayList源码

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    transient Object[] elementData;

    E elementData(int index) {
        return this.elementData[index];
    }
}

而我的代码却无法编译

ArrayList的get()方法为什么可以直接将Object数组返回成泛型里的类型?

回复
1个回答
avatar
test
2024-06-18

你这个代码是不是通过 IDE 里的 go to definition 看到的。

对 ArrayList ,这种方式看到的不是实际代码,而是通过反汇编得到的。

而对于这类 generic 函数,类型检查实际上貌似是在最终不再有 generic 类型的调用处发生的,而不是被调函数里。所以反汇编的代码里就看不到类型转换了。

但是实际代码,没有类型转化是无法通过编译的。

这应该是由于类型擦除,在 elementData 函数体是无法得到 E 具体是什么类型的,也就无法进行实际的转换。实际的转换要一直延迟到可以确定 E 的位置才能发生。


package foo;

public class Generic<T> {
    public T getObjectFoo() {
        return (T) new Object();
    }
}

javap -c Generic.class

Compiled from "Generic.java"
public class foo.Generic<T> {
  public foo.Generic();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public T getObjectFoo();
    Code:
       0: new           #3                  // class java/lang/Object
       3: dup
       4: invokespecial #8                  // Method java/lang/Object."<init>":()V
       7: areturn
}
package foo;

public class Foo {
    public void A() {
        final Generic<Integer> g = new Generic<>();
        final Integer i = g.getObjectFoo();
    }
}

javap -c Foo.class

Compiled from "Foo.java"
public class foo.Foo {
  public foo.Foo();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public void A();
    Code:
       0: new           #15                 // class foo/Generic
       3: dup
       4: invokespecial #17                 // Method foo/Generic."<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #18                 // Method foo/Generic.getObjectFoo:()Ljava/lang/Object;
      12: checkcast     #22                 // class java/lang/Integer  !!!! 实际的类型检查(转换)
      15: astore_2
      16: return
}

可以看到类型检查(转换)的代码是在 Foo.A 里,而不在 Generic.getInteger 里。所以如果是对 Generic.getInteger 进行反汇编,可能就看不到里面的类型转换了。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容