一个编译器必须翻译一个通用类型或方法(不仅限于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[]
转换为数组是向用户发出警告,表明转换可能不相关的唯一方法。实际上,在这里,我们最终将 Object[]
向下转换为 String[]
,这导致运行时出现 ClassCastException
。
因此,对于那些说“编译器在方法调用行应用显式转换难道不足够了”的人,答案是:
开发人员并不掌握这种转换,因为它是在编译步骤中自动创建的,所以这个运行时特性不能警告用户在启动编译之前深入检查代码的安全性。
简而言之,这种转换是值得存在的。
t
是什么? - Bhesh Gurungt
只是Test
示例类的一个实例。它只是上面整个代码的一部分。 - Mik378