[英]How does Java type erasure work when the type parameter is used for casting?
I know generally unbound type parameters are substituted with Object
in compile time.我知道通常未绑定的类型参数在编译时被Object
替换。 But how does this piece of code work?但是这段代码是如何工作的呢?
<T> void call(List<T> list, Object o) {
fun((T) o);
}
Will it be compiled to会编译成
void call(List list, Object o) {
fun((Object) o);
}
Which seems like a wrong case because o
should be cast to the same type as the elements in list?这似乎是一个错误的情况,因为o
应该转换为与列表中的元素相同的类型?
Because of type erasure even if your type is A
, it will be treated as Object
in your example as you guessed.由于类型擦除,即使您的类型是A
,在您的示例中它也将被视为Object
,正如您所猜测的那样。 which means if you passed your second elem other than A
, it will actually be casted to Object
.这意味着如果您通过了A
以外的第二个元素,它实际上将被转换为Object
。
Example,例子,
import java.util.ArrayList;
import java.util.List;
public class TypeErasure {
static <A> void call(List<A> list, Object elem) {
A o1 = (A) elem;
System.out.println(o1);
}
static void callV2(List list, Object elem) {
System.out.println(elem);
}
//bounded type
static <A extends Number> void callV3(List<A> list, Object elem) {
A o1 = (A) elem;
System.out.println(o1);
}
public static void main(String[] args) {
call(new ArrayList<Integer>(), "trying to cast string to Integer");
callV2(new ArrayList<Integer>(), "trying to cast string to Integer");
//will be casted to Number
callV3(new ArrayList<Integer>(), 1);
callV3(new ArrayList<Double>(), 1.5);
callV3(new ArrayList<Long>(), 1L);
// following will fail at runtime with ClassCastException
/* Exception in thread "main" java.lang.ClassCastException:
class java.lang.String cannot be cast to class java.lang.Number
(java.lang.String and java.lang.Number are in
module java.base of loader 'bootstrap')
*/
callV3(new ArrayList<Integer>(), "trying to cast string to Integer");
}
}
No, because type information is available in java only in runtime, hence it won't compile to anything more specific than Object
.不,因为类型信息仅在运行时在 java 中可用,因此它不会编译为比Object
更具体的任何内容。 Other case would be, if type parameter T
was bound, for example:其他情况是,如果类型参数T
被绑定,例如:
<T extends Number> void call(List<T> list, Object o) {
fun((T) o);
}
Then the compiler doesn't know the exact type at compile time, but it does know it's a subtype of Number
, so if method fun
consumed Number
as parameter, it would compile as opposed to the first example.然后编译器在编译时不知道确切的类型,但它确实知道它是Number
的子类型,因此如果方法fun
使用Number
作为参数,它将与第一个示例相反进行编译。
Will it be compiled to会编译成
No, no cast will be inserted if the bound is Object
, because a cast to Object
always succeeds.不,如果绑定为Object
则不会插入任何类型转换,因为转换为Object
总是成功的。
If the type variable were bounded, eg T extends Number
, then a checkcast
instruction would be inserted to ensure that o
is a Number
, equivalent to (Number) o
.如果类型变量是有界的,例如T extends Number
,那么将插入一个checkcast
指令以确保o
是一个Number
,相当于(Number) o
。
You may notice that the compiler generates a unchecked warning on that line.您可能会注意到编译器会在该行生成未经检查的警告。 An unchecked warning means that the compiler is unable to insert a bytecode to ensure that o
is an instance of T
, specifically.未经检查的警告意味着编译器无法插入字节码以确保o
是T
的实例。
It's also worth pointing out that the type variable is redundant.还值得指出的是类型变量是多余的。 You can use the following, and it will be equivalent:您可以使用以下内容,这将是等效的:
void call(List<?> list, Object o) {
fun(o);
}
The cast is unnecessary, since fun
must be able to accept any Object
anyway.演员表是不必要的,因为fun
必须能够接受任何Object
无论如何。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.