通用java擦除如何影响newInstance()的使用?

时间:2016-06-24 12:59:17

标签: java generics erasure

基于java文档:

  

在类型擦除过程中,Java编译器会擦除所有类型   参数并用类型的第一个边界替换每个参数   参数是有界的,如果类型参数是无界的,则为Object。

现在,事情就是这样的一个类:

public class MyCreator<T> { 
    Class<T> kind; 

    MyCreator(Class<T> kind) {
        this.kind = kind; 
    }

    void printInstanceClass() throws Exception{ 
        System.out.println(kind.newInstance().getClass());
    }

    public static void main(String[] args) throws Exception{ 
        MyCreator<String> myCreator = new MyCreator<String>(String.class);

        myCreator.printInstanceClass();
    } 
}

printInstanceClass()方法实际打印“class java.lang.String”。

如果编译器正在使用Object替换类内部的T,我想也会删除与kind关联的类的信息并替换为Class。那么,newInstance()方法如何返回String实例而不是Object 1?

3 个答案:

答案 0 :(得分:2)

你传递了String.class(它没有被删除,但是在运行时保留了一个具体的类),然后在该类上调用newInstance,这会产生一个String。

输出检查具体对象(String)并显示其类。

答案 1 :(得分:2)

棘手的部分是String.class 参数。它不是类型参数,而是一个普通的旧参数,如String[] args。因此,Class<T> kind将为String.class,因此printInstanceClass()可以在运行时访问它。

这是一种常见做法,也在Effective Java中提出。

因此,在类型擦除之后,此代码在逻辑上等同于此代码:

public class MyCreator { 
    Class kind; // this will be String.class at runtime

    MyCreator(Class kind) {
        this.kind = kind; 
    }

    void printInstanceClass() throws Exception{ 
        System.out.println(kind.newInstance().getClass());
    }

    public static void main(String[] args) throws Exception{ 
        MyCreator myCreator = new MyCreator(String.class);

        myCreator.printInstanceClass();
    } 
}

答案 2 :(得分:1)

有关作为myCreator对象的通用参数传递的类(类型)的信息将被删除,但不会存储kind对象中存储的信息。

使用Class<?>对象方法很好,但如果您尝试从通用T类型获取类信息,则会遇到编译错误,例如:

void printInstanceClass() throws Exception{ 
    System.out.println(T.class.newInstance().getClass()); // error!
}

虽然这并不容易,但也存在执行上述操作的解决方法。