[英]java generics type erasure
When declaring a class with type parameter <T extends A & B & C>
,type erasure process will replace T
with type A
. 当声明类型参数<T extends A & B & C>
的类<T extends A & B & C>
,类型擦除过程将用类型A
替换T
But if variable of type T
calls method declaring in interface B
or C
, what does Java do with it? 但是如果T
类型的变量调用接口B
或C
方法声明,Java会用它做什么?
And when we create an instance of generic type such as ArrayList<String>
, the type parameter String
will also be erased, but calling get
method will return type String
, where does this information come from since it has been erased ? 当我们创建一个泛型类型的实例,如ArrayList<String>
,类型参数String
也将被删除,但是调用get
方法将返回类型String
,这些信息来自哪里,因为它已被删除?
I know java reflection is used, but I need some specific explanation. 我知道使用java反射,但我需要一些具体的解释。
Reflection isn't used - casting is. 不使用反射 - 铸造是。 For example, take this code: 例如,请使用以下代码:
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();
}
}
Now look at the bytecode for Generic
(constructor removed): 现在看一下Generic
的字节码(删除了构造函数):
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
}
Note the checkcast
instructions before each of the invokeinterface
calls to b()
and c()
. 请注意每个invokeinterface
调用b()
和c()
之前的checkcast
指令。
The result is exactly as if Generic
were actually written like this: 结果就像Generic
实际上是这样编写的:
class Generic<T extends A> {
T t;
Generic(T t) {
this.t = t;
}
void callMethods() {
t.a();
((B) t).b();
((C) t).c();
}
}
As for your question about ArrayList
- the information about the return type of get()
being the element type of the list is still stored as part of the ArrayList
class. 至于你关于ArrayList
的问题 - 关于作为列表元素类型的get()
的返回类型的信息仍然存储为ArrayList
类的一部分。 The compiler will again insert casts in the calling code, so: 编译器将再次在调用代码中插入强制转换,因此:
ArrayList<String> strings = new ArrayList<String>();
strings.add("foo");
String x = strings.get(0);
is equivalent at execution time to: 在执行时相当于:
ArrayList strings = new ArrayList();
strings.add("foo");
String x = (String) strings.get(0);
One important aspect of this is that you can't ask an ArrayList
object at execution time what T
is - that information has been erased. 这个的一个重要方面是你不能在执行时询问一个ArrayList
对象是什么T
- 该信息已被删除。
Type erasure effectively replaces all the generic type parameters with Object
after the compiler has done its type checking. 在编译器完成类型检查后,类型擦除有效地用Object
替换所有泛型类型参数。 In your <T extends A & B & C>
example, A
is erased just like everything else. 在你的<T extends A & B & C>
示例中, A
就像其他所有内容一样被删除。
When you call get
on an ArrayList<String>
, the compiler produces bytecode that casts the returned object to a string automatically. 当您在ArrayList<String>
上调用get
时,编译器会生成字节码,将返回的对象自动转换为字符串。 The list itself doesn't "know" that it's a list of strings (due to the type erasure), but the code that calls get
knows that it expects the thing gotten from the list to be a string. 列表本身并不“知道”它是一个字符串列表(由于类型擦除),但是调用get
的代码知道它希望从列表中get
的东西是一个字符串。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.