必须翻译泛型类型或方法(任何语言,而不仅仅是 Java)的编译器原则上有两种选择:
代码专业化。编译器为泛型类型或方法的每个实例化生成一个新的表示。例如,编译器将为整数列表生成代码,并为字符串列表、日期列表、缓冲区列表等生成其他不同的代码。
代码共享。编译器仅为泛型类型或方法的一种表示生成代码,并将泛型类型或方法的所有实例化映射到唯一表示,在需要时执行类型检查和类型转换。
Java使用代码共享方法。我相信 C# 遵循代码专业化方法,因此根据我使用 C# 的情况,下面的所有代码都是合乎逻辑的。
假设这个 Java 代码片段:
public class Test {
public static void main(String[] args) {
Test t = new Test();
String[] newArray = t.toArray(new String[4]);
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
//5 as static size for the sample...
return (T[]) Arrays.copyOf(a, 5, a.getClass());
}
}
代码共享方法会在类型擦除发生后导致此代码:
public class Test {
public static void main(String[] args) {
Test t = new Test();
//Notice the cast added by the compiler here
String[] newArray = (String[])t.toArray(new String[4]);
}
@SuppressWarnings("unchecked")
public Object[] toArray(Object[] a) {
//5 as static size for the sample...
return Arrays.copyOf(a, 5, a.getClass());
}
}
所以我的问题是:
需要什么来精确这个初始演员阵容?:
(T[]) Arrays.copyOf(a, 5, a.getClass());
而不是简单地做(在类型擦除之前,在编码时):
Arrays.copyOf(a, 5, a.getClass());
编译器真的需要这种强制转换吗?
好的,在没有明确向下转换的情况下,Arrays.copyOf
返回Object[]
并且不能被更具体的类型直接引用。
但是编译器不能在这种情况下做出努力,因为它处理的是泛型类型(返回类型!)?
实际上,编译器对方法的调用者行应用显式强制转换还不够吗?:
(String[])t.toArray(new String[4]);
更新 - - - - - - - - - - - - - - - - - - - - - - - - - --------------------
感谢@ruakh 的回答。
这里有一个示例证明了显式转换甚至只是在编译时出现是相关的:
public static void main(String[] args) {
Test t = new Test();
String[] newArray = t.toArray(new String[4]);
}
public <T> T[] toArray(T[] a) {
return (T[]) Arrays.copyOf(a, 5, Object[].class);
}
投射到T[]
是向用户发出一些警告的唯一方法,表明投射可能不相关。事实上,在这里我们最终得到了 to 的向下转换Object[]
,String[]
这导致了ClassCastException
运行时的 a。
所以,说到“编译器对方法的调用者行应用显式转换还不够”,答案是:
开发人员不掌握此转换,因为它是在编译步骤自动创建的,因此此运行时功能不会警告用户在启动编译之前深入检查其代码的安全性。
简而言之,这个演员阵容值得出席。