无法理解Java中的泛型编程。
我读了一些关于它的教程,但仍然很困惑,特别是当事情变得复杂时。
有人能解释一下这个例子中发生了什么吗?
import java.util.Date;
public class Test1 {
public static void main(String[] args) {
P<Cls> p = new P<>(); //<1> //I expect a ClassCastException here, but no. Why? //How does the type inference for class P<E> work?
System.out.println(p.name); //it prints
// System.out.println(p.name.getClass());//but this line throws ClassCastException //why here? why not line <1>?
test1(p);//it runs
// test2(p);//throws ClassCastException//What is going on in method test1&test2?
//How does the type inference for generic methods work in this case?
}
public static<T> void test1(P<? extends T> k){
System.out.println(k.name.getClass());
}
public static<T extends Cls> void test2(P<? extends T> k){
System.out.println(k.name.getClass());
}
}
class P<E>{
E name = (E)new Date();//<2>
}
class Cls{}
答案 0 :(得分:2)
P<Cls> p = new P<>();
请记住,Java通过 erasure 实现了泛型,这意味着 P
的构造函数并不知道E
在运行时是什么。 Java中的泛型纯粹是为了在编译时帮助开发人员。
这意味着当您创建new P<>()
时,会创建一个new Date()
但它实际上并没有转换为任何特定类型,因为运行时对{ {1}} 的。就E
类而言,E
在运行时不存在。 P<E>
只是name
引用,内部有Object
。但是,每当您编写以运行时环境需要知道它属于特定类型(在这种情况下为Date
)的方式使用name
的代码时,编译器会将转换插入到该类型而不会告诉你。
Cls
被编译为p.name.getClass()
,这将创建一个类强制转换异常。((Cls)p.name).getClass()
指定非通用的类型约束(test2()
)。因此,对extends Cls
的调用同样会转换为p.name.getClass()
。另一方面:
((Cls)p.name).getClass()
实际上与System.out.println(p.name)
相同,因为System.out.println((Object)p.name)
是一种采用println
的非泛型方法。object
类似。因为运行时实际上并不知道test1(p.name)
是什么类型,所以它基本上将T
强制转换为p.name
,然后再调用Object
。换句话说,这是你实际编译的代码:
getClass()