Java generictyped方法返回错误的类型
每隔一段时间,我就觉得自己根本不懂Java。。我最近发现了Java类型转换的这种奇怪行为:
public static void main(String[] args) {
String res = get();
System.out.println(res);
}
public static <T> T get() {
Object longObj = Long.valueOf("0");
T casted = (T) longObj;
System.out.println("longObj=" + longObj.getClass());
System.out.println("casted=" + casted.getClass()); // <-- Why the type of "casted" is Long instead of String???
return casted;
}
输出为:
longObj=class java.lang.Long
casted=class java.lang.Long
Exception in thread "main" java.lang.ClassCastException: java.lang.Long
cannot be cast to java.lang.String
at com.apple.geo.coreloc.Test.main(Test.java:5)
我的困惑是:为什么变量casted
的类型是Long
?它不应该被强制转换为类型T
,即String
吗
以下是我认为应该是String
的原因:
- 在运行时,
String res = get()
提示get()方法返回字符串 T casted = (T) longObj;
应该尝试将cast Long键入字符串(我希望这里出现异常,但没有…)李>
# 1 楼答案
java泛型与C++模板不同。对于Java泛型方法,该方法只有一个版本。在C++中,模板化方法的代码根据特定类型需要生成,以便每个不同的参数化类型获得该方法的自己版本。p>
要获得预期的错误,必须告诉Java泛型类型,从而帮助Java解决问题
运行此命令会出现强制转换异常:
# 2 楼答案
铸造不同于转化
强制转换是一种声明,表明对象属于目标类型。它不会更改当前对象的类
转换是将一种类型的对象重新创建为另一种类型的对象的过程
这就是为什么只有当你已经知道你正在铸造的对象的类型时,才应该使用铸造。在所有其他情况下,应该将对象转换为目标类型的实例
# 3 楼答案
在Java中,泛型类型只在编译时工作,但由于所谓的“类型擦除”(参见here和here),它(几乎)没有关于特定目标泛型类型的信息
如果反编译代码,您将看到:
这里一切都很清楚:
main
中,这只是强制转换操作get
中,带有“casted”值的变量被完全删除# 4 楼答案
泛型是编译时检查。它们不是写糟糕演员阵容的保障
你试着做
(String) longIbj;
,而longObj
是一个很长的过程。这会给你一个运行时ClassCastException
但是,因为它不是
T get()
上下文中的编译时错误,所以T get()
被正确编译。由于“类型擦除”,T被提升为最高约束类型。您没有限制类型的上限,因此编译器处理的代码大致如下:由于
<T>
是一个Object
,填充longObj
和casted
的两行代码大致相同。在任何情况下,通过任何名称对对象引用的多态调用仍将解析为对象的.getClass()
方法,该方法仍将返回java.lang.Long
Java中的强制转换不会创建新对象。如果你想要一个不同的对象,你需要类型的变量调用它)
new
一个不同的对象,并用相关信息填充它。java中的强制转换只能通过强制转换类型的方法名访问类。因此,在Long
转换为Object
时,您可能会丢失getLong()
,但它仍然存在(如果您通过^{