Java 泛型类型擦除:何时发生以及会发生什么? [英] Java generics type erasure: when and what happens?

查看:39
本文介绍了Java 泛型类型擦除:何时发生以及会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Oracle 的网站上阅读了有关 Java 类型擦除的信息.

I read about Java's type erasure on Oracle's website.

类型擦除何时发生?在编译时还是运行时?类何时加载?类什么时​​候实例化?

When does type erasure occur? At compile time or runtime? When the class is loaded? When the class is instantiated?

很多网站(包括上面提到的官方教程)都说编译时会发生类型擦除.如果在编译时完全去掉了类型信息,那么当调用使用泛型的方法没有类型信息或错误类型信息时,JDK如何检查类型兼容性?

A lot of sites (including the official tutorial mentioned above) say type erasure occurs at compile time. If the type information is completely removed at compile time, how does the JDK check type compatibility when a method using generics is invoked with no type information or wrong type information?

考虑以下示例:假设 class A 有一个方法 empty(Box<? extends Number> b).我们编译A.java,得到类文件A.class.

Consider the following example: Say class A has a method, empty(Box<? extends Number> b). We compile A.java and get the class file A.class.

public class A {
    public static void empty(Box<? extends Number> b) {}
}

public class Box<T> {}

现在我们创建另一个类B,它使用非参数化的参数(原始类型)调用方法empty:empty(new Box()).如果我们在类路径中使用 A.class 编译 B.java,javac 足够聪明,可以发出警告.所以 A.class 一些类型信息存储在其中.

Now we create another class B which invokes the method empty with a non-parameterized argument (raw type): empty(new Box()). If we compile B.java with A.class in the classpath, javac is smart enough to raise a warning. So A.class has some type information stored in it.

public class B {
    public static void invoke() {
        // java: unchecked method invocation:
        //  method empty in class A is applied to given types
        //  required: Box<? extends java.lang.Number>
        //  found:    Box
        // java: unchecked conversion
        //  required: Box<? extends java.lang.Number>
        //  found:    Box
        A.empty(new Box());
    }
}

我的猜测是在加载类时会发生类型擦除,但这只是一个猜测.那么什么时候发生呢?

My guess would be that type erasure occurs when the class is loaded, but it is just a guess. So when does it happen?

推荐答案

类型擦除适用于泛型的使用.类文件中肯定有元数据来说明方法/类型是否泛型,以及约束是什么等等.但是当泛型被使用时,它们会被转换进入编译时检查和执行时强制转换.所以这段代码:

Type erasure applies to the use of generics. There's definitely metadata in the class file to say whether or not a method/type is generic, and what the constraints are etc. But when generics are used, they're converted into compile-time checks and execution-time casts. So this code:

List<String> list = new ArrayList<String>();
list.add("Hi");
String x = list.get(0);

被编译成

List list = new ArrayList();
list.add("Hi");
String x = (String) list.get(0);

在执行时,无法找出列表对象的 T=String - 该信息已消失.

At execution time there's no way of finding out that T=String for the list object - that information is gone.

...但是 List 接口本身仍然标榜自己是通用的.

... but the List<T> interface itself still advertises itself as being generic.

澄清一下,编译器确实保留了关于 变量List 的信息 - 但你仍然无法发现 T=String 用于列表对象本身.

Just to clarify, the compiler does retain the information about the variable being a List<String> - but you still can't find out that T=String for the list object itself.

这篇关于Java 泛型类型擦除:何时发生以及会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆