首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java泛型类型擦除

java泛型类型擦除
EN

Stack Overflow用户
提问于 2011-11-01 14:51:11
回答 2查看 416关注 0票数 3

在声明带有类型参数<T extends A & B & C>的类时,类型擦除过程将用类型A替换T。但是,如果T类型的变量调用接口BC中的方法声明,那么它会做什么呢?

当我们创建一个泛型类型的实例时,比如ArrayList<String>,类型参数String也会被擦除,但是调用get方法会返回类型String,既然它已经被擦除了,那么这个信息从哪里来呢?

我知道使用了java反射,但我需要一些具体的解释。

EN

回答 2

Stack Overflow用户

发布于 2011-11-01 15:04:13

不使用反射,而是使用强制转换。例如,以下面的代码为例:

代码语言:javascript
复制
interface A {
    void a();
}

interface B {
    void b();
}

interface C {
    void c();
}

class Generic<T extends A & B & C> {
    T t;

    Generic(T t) {
        this.t = t;
    }

    void callMethods() {
        t.a();
        t.b();
        t.c();
    }
}

现在看看Generic的字节码(删除了构造函数):

代码语言:javascript
复制
class Generic extends java.lang.Object{
A t;

void callMethods();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field t:LA;
   4:   invokeinterface #3,  1; //InterfaceMethod A.a:()V
   9:   aload_0
   10:  getfield        #2; //Field t:LA;
   13:  checkcast       #4; //class B
   16:  invokeinterface #5,  1; //InterfaceMethod B.b:()V
   21:  aload_0
   22:  getfield        #2; //Field t:LA;
   25:  checkcast       #6; //class C
   28:  invokeinterface #7,  1; //InterfaceMethod C.c:()V
   33:  return    
}

注意每个invokeinterface调用b()c()之前的checkcast指令。

结果就像Generic实际上是这样写的:

代码语言:javascript
复制
class Generic<T extends A> {
    T t;

    Generic(T t) {
        this.t = t;
    }

    void callMethods() {
        t.a();
        ((B) t).b();
        ((C) t).c();
    }
}

至于您提出的关于ArrayList的问题--关于get()的返回类型是列表的元素类型的信息仍然作为ArrayList类的一部分存储。编译器将再次在调用代码中插入类型转换,因此:

代码语言:javascript
复制
ArrayList<String> strings = new ArrayList<String>();
strings.add("foo");
String x = strings.get(0);

在执行时等同于:

代码语言:javascript
复制
ArrayList strings = new ArrayList();
strings.add("foo");
String x = (String) strings.get(0);

这样做的一个重要方面是,您不能在执行时询问ArrayList对象T是什么--该信息已被擦除。

票数 6
EN

Stack Overflow用户

发布于 2011-11-01 15:06:50

在编译器完成类型检查之后,类型擦除可以有效地将所有泛型类型参数替换为Object。在您的<T extends A & B & C>示例中,A被擦除,就像其他所有东西一样。

ArrayList<String>上调用get时,编译器会生成自动将返回的对象转换为字符串的字节码。列表本身并不“知道”它是一个字符串列表(由于类型擦除),但是调用get的代码知道它期望从列表中获得的东西是一个字符串。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7963324

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档