我正在学习" Java in a Nutshell"第5版。在p169,它说"记住, 但是,类型变量仅在编译时存在,因此您不能使用类型变量 与运行时运算符instanceof和new。"。如果我理解正确(我是??),new和instanceof不应该与类型变量一起使用。但在我做了一些测试后,我变得更加困惑。
有谁可以告诉我为什么(2)被允许?
非常感谢任何信息。
答案 0 :(得分:7)
声明“您不能将类型变量与new
一起使用”意味着您无法执行此操作:
E e = new E(); // can't do this
但是你可以将类型变量传递给另一个类供它使用:
class MyClass<E> {
List<E> = new ArrayList<E>(); // OK
}
您不是实例化 E
,而是使用类型 ArrayList
实例化E
。
关于使用?
,这是一个不同的问题。 ?
表示“未知”类型,而变量可以是未知类型,您不能通过指定未知类型实例化泛型类 - 您必须将已知的类型传递给泛型类。
但你可以编码:
List<?> list = new ArrayList<E>();
答案 1 :(得分:2)
除非您已定义,E
不是一个类。
E
只是在编译期间引用类的一种方法。这样,可以用它调用适当的方法。
List<String> list1 = new ArrayList<String>(); // Diamond types for Java 7+
List<Integer> list2 = new ArrayList<Integer>();
// Populate lists
list1.get(0).charAt(0); // Perfectly fine, String#charAt(int) exists
list2.get(0).charAt(0); // Error! Integer doesn't have a charAt(int) method!
因此,E
类中的类型ArrayList
用于确保您可以在知道类型的情况下对元素执行操作,就好像它是该类型一样。这样可以避免在调用仅存在于特定类中的方法时遇到问题,正如我使用charAt(int)
方法所示。
除此之外,还可以指出为什么你不能使用?
拨打电话。
List<?> list1 = new ArrayList<String>(); // Fine
List<?> list2 = new ArrayList<?>(); // What type is this list composed of?
制作未知类型的列表没有意义。如果您想要一个泛型类型的列表,您始终可以将Object
传递给泛型,但没有理由添加对创建具有未知类型的实例的支持。
答案 2 :(得分:0)
波西米亚人回答了一些“什么”,但我想对一些“为什么”采取行动。
让我们从无法做的事情开始吧。这一切都归结为erasure,这基本上意味着当您的代码有List<String>
时,字节码信息只有List
。字节码中缺少尖括号之间的任何内容(因此也没有来自运行时)。
那么,为什么你不能foo instanceof E
?好吧,因为那是运行时检查,并且E
在运行时是未知的。
为什么你不能new E()
?同样,因为这需要运行时知道E
是什么(它如何调用正确的构造函数?或者甚至确保存在无参数构造函数?),但该信息不可用。< / p>
在所有这些情况下,要记住的是,语言不会阻止您仅仅为了阻止您而做某事。它阻止你这样做,因为它不可能在运行时执行。
那么,为什么 你可以输入new ArrayList<String>()
?因为运行时需要的唯一信息是ArrayList
被实例化,并且它具有该信息。它是ArrayList
String
的事实对运行时无关紧要,因为擦除意味着ArrayList
在运行时不知道或不关心它是什么的列表