Java 为什么我必须强制转换为泛型类型T,即使我知道它返回正确?
我的代码:Java 为什么我必须强制转换为泛型类型T,即使我知道它返回正确?,java,generics,Java,Generics,我的代码: private static <T> T get(Class<T> clazz) throws IllegalAccessException, InstantiationException { if (clazz.equals(String.class)) { return (T) new String("abc");//line x } else { return clazz.n
private static <T> T get(Class<T> clazz) throws IllegalAccessException, InstantiationException {
if (clazz.equals(String.class)) {
return (T) new String("abc");//line x
} else {
return clazz.newInstance();
}
}
private static T get(Class clazz)抛出IllegaccessException、InstanceionException{
if(clazz.equals(String.class)){
返回(T)新字符串(“abc”);//第x行
}否则{
返回clazz.newInstance();
}
}
如您所见,在行x
中,T
必须是String.class
并返回String
。但是编译失败,没有将结果强制转换为T
将
行x
更改为返回新字符串(“abc”)代码>结果不兼容类型
编译器不考虑if
语句
因此,它所看到的是,您需要返回一个T
(它对此没有进一步的了解)。它没有推断这里的T
必须是String
通过执行以下操作,可以避免出现“未选中强制转换为已擦除类型”的警告
原因是您不能为每个类强制转换字符串。假设T是一个数字类,你会抛出一个ClassCastException
您可以尝试以下方法来解决问题:
return (T) ((Object) new String("abc"));
您可以按如下方式避免强制转换:
if (clazz.equals(String.class)) {
return clazz.getDeclaredConstructor(String.class).newInstance("abc");
}
return clazz.newInstance();
您必须捕获(并忽略)一些异常。这并不是模板的真正用途。当然,对您来说很明显,它总是返回类型为T的内容-但是对编译器来说这是显而易见的吗?如果T不是字符串,则仍有一些路径(可访问或不可访问)返回错误的类型。这不会产生相同的结果。OP的代码每次都创建一个新的字符串实例,但您的代码每次都返回相同的(插入的)字符串。可能clazz.cast(新字符串(“abc”)代码>还应注意,调用cast()仍然涉及不安全的强制转换,但它隐藏在cast方法中。@Bohemian:我悄悄地自动更正了新字符串()
部分。在大多数情况下,您不需要新的字符串实例。cast
在这里并不是不安全的,因为if
语句已经检查了类型兼容性(这是这个问题的重点,我认为其他一些语言有更强的类型推断,考虑到了这种条件)。对不起,“不安全”从实际的角度来看并不是指不安全,而是编译器认为它不安全并生成警告。具体来说,cast()
方法不返回(T)obj代码>并用@SuppressWarnings(“unchecked”)
-调用cast()
只是将警告从代码中推到JDK中(我对此很酷-我自己经常使用这种模式)。我想说的(以及OP显然期望的)这可能被认为是编译器的一个缺点,它认为原始代码中的强制转换不安全,并生成警告。在一个条件块内部,比如问题中的代码中,强制转换永远不会失败。有些系统确实支持这种推断。以Eclipse为例,它将在中的狭窄类型上自动完成方法,如果(某物的x实例){
(并自动插入编译器所需的强制转换)。@Bohemian:通过使用cast()
,您可以“隐藏”未经检查的强制转换,这样您就不会再看到警告,但它同样不安全。但事实并非如此。Java标准库API永远不会允许您在没有警告的情况下执行不安全的操作(其中不安全包括堆污染之类的内容)。什么cast()
的内部代码并不重要——重要的是它的API——它的API不允许您使用它造成堆污染,而未经检查的强制转换是不安全的,因为它可能导致堆污染。
if (clazz.equals(String.class)) {
return clazz.getDeclaredConstructor(String.class).newInstance("abc");
}
return clazz.newInstance();