简体   繁体   English

java泛型中类型擦除的逻辑是什么?

[英]what is the logic of type erasure in java generics?

As far as I know, type generics happens in the following code:据我所知,类型泛型发生在以下代码中:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

when the compiler compiles the code, the generic types will be erased so all the signatures are exactly same, which looks as follows:当编译器编译代码时,泛型类型将被擦除,因此所有签名完全相同,如下所示:

public class Test {

    public void a(List list) {
    }

    public void a(List list){
    }

    public void a(List list){
    }

}

If this is the logic, then:如果这是逻辑,那么:

List<Object> objList = new ArrayList<>();
List<String> strList = new ArrayList<>();
objList = strList;  

is actually:实际上是:

List objList = new ArrayList<>();
List strList = new ArrayList<>();
objList = strList; 

which is OK because both of the two lists are same type.这是可以的,因为两个列表都是相同的类型。 However, In the above code, objList = strList will result an error.但是,在上面的代码中, objList = strList会导致错误。

Not quite sure what is the real logic.不太确定什么是真正的逻辑。 And what is more, the difference between List<?> , List(without any braces) and List< Object>更重要的是, List<?> 、 List(不带大括号)和List< Object>之间的区别

Generics are invariant: for any two distinct types U and V , List<U> is neither a subtype nor a supertype of List<V> .泛型是不变的:对于任何两个不同的类型UVList<U>既不是List<V>的子类型也不是超类型。 (Joshua Bloch, Effective Java) (Joshua Bloch, Effective Java)

You can't put any value except null into a List<?> .您不能将除null之外的任何值放入List<?>

The diff between List<?> and List is the former can take any type either an Object class or any other object. List<?> 和 List 之间的区别在于前者可以采用 Object 类或任何其他对象的任何类型。 The latter can take only object后者只能带对象

List<Object> list = new ArrayList<String> // compile error

List<?> list = new ArrayList<String>  //no error

List<?extends Comparator> (boundedd) will get converted to List after compile List Unbounded are converted to Object whereas for bounded the Java compiler replaces the bounded type parameter T with the first bound class. List<?extends Comparator> (boundedd) 将在编译 List Unbounded 转换为 Object 后转换为 List,而对于 bounded,Java 编译器将有界类型参数 T 替换为第一个绑定类。

For more details Generics有关详细信息泛型

To complement @Giorgi Tsiklauri's answer ,为了补充@Giorgi Tsiklauri 的回答

For the class below:对于下面的类:

class Box<T> {
    T t;

    T getT() { return t; }

    void setT(T t) { this.t = t; }
}

because of type erasure, compiler compiles the class to:由于类型擦除,编译器将类编译为:

class Box {
    Object t;

    Object getT() { return t; }

    void setT(Object t) { this.t = t; }
}

So, when you instantiate the Box<T> generic class with type argument Integer as follows:因此,当您使用类型参数Integer实例化Box<T>泛型类时,如下所示:

Box<Integer> box = new Box<Integer>();
box.setT(10);
Integer t = box.getT();

the compiler knows that the Box<T> is instantiated with Integer because, at compile time, it sees that Box<Integer> .编译器知道Box<T>是用Integer实例化的,因为在编译时,它看到Box<Integer> So, type casts are inserted by compiler.因此,类型转换由编译器插入。 So the code above is compiled into:所以上面的代码被编译成:

Box box = new Box();
box.setT(10);
Integer t = (Integer) box.getT(); // compiler inserts type casts in lieu of us!

No matter how you instantiate the generic, the compiler doesn't create additional class files.无论您如何实例化泛型,编译器都不会创建额外的类文件。 If what actually happens at type erasure is replacement(replaces T with type argument such as Integer ), the compiler have to create additional classes for Box for Integer , Box for Double etc — But that's not what actually happens at type erasure:如果在类型擦除时实际发生的是替换(用Integer等类型参数替换T ),编译器必须为Box for IntegerBox for Double等创建额外的类——但这不是在类型擦除时实际发生的情况:

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded.如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或Object The Java™ Tutorials Java™ 教程

Insert type casts if necessary to preserve type safety.必要时插入类型转换以保持类型安全。 The Java™ Tutorials Java™ 教程

Type erasure ensures that no new classes are created for parameterized types;类型擦除确保不会为参数化类型创建新类; consequently, generics incur no runtime overhead.因此,泛型不会产生运行时开销。 The Java™ Tutorials Java™ 教程

If this is the logic, then..如果这是这个逻辑,那么..

No, that is not what happens.不,这不是发生的事情。

Type erasure is a process that takes place during compilation, and for specific object allocations (objects, created using new ), compiler erases all the generic type parameters (eg Box<T> ) with corresponding generic type arguments (eg Box<Integer> ).类型擦除是在编译期间发生的一个过程,对于特定的对象分配(对象,使用new创建),编译器擦除所有具有相应泛型类型参数(例如Box<Integer> )的泛型类型参数(例如Box<T> Box<Integer> ) .

This means, that if you have defined your class:这意味着,如果你已经定义了你的类:

class Box<T> {
}

and then invoked that type (instantiated), as:然后调用该类型(实例化),如:

Box<Integer> intBox = new Box<>();

in the compiled version, instantiation of intBox will allocate the object, on the heap, having swapped all the appearances of T with Integer .在编译版本中, intBox实例化将在堆上分配对象,将T所有外观与Integer交换。

Therefore, in your example:因此,在您的示例中:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

you are invoking a parametrized type (generic) and you declare method's local parameter with generic type argument .您正在调用参数化类型(泛型)并使用泛型类型参数声明方法的局部参数。

For the object referenced by the variable of type List<String> , compiler have erased all the appearances of List 's E with String , and for List<Integer> - E will be replaced by Integer .对于List<String>类型的变量所引用的对象,编译器已经用String擦除了ListE所有外观,对于List<Integer> - E将替换为Integer

For the final part of your confusion, I'd suggest you read this .对于您困惑的最后一部分,我建议您阅读此内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM