输入以下代码:
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
HashMap<String, Object> dataMap = new HashMap<>();
dataMap.put("longvalue", 5L);
class TestMethodHolder {
<T> T getValue(Map<String, Object> dataMap, String value) {
return (T)dataMap.get(value);
}
}
hashMap.put("test", new TestMethodHolder().<String>getValue(dataMap, "longvalue"));
String value = hashMap.get("test"); // ClassCastException occurs HERE
System.out.println(value);
}
对我来说,这段代码可以编译并不奇怪,但是ClassCastException发生在get行而不是它上面的put行,尽管我确实对可能发生的事情有一个有根据的猜测。由于在运行时会擦除泛型类型,因此getValue()中的强制转换实际上从不会在运行时发生,并且实际上是对Object的强制转换。如果按以下方式实现该方法,则将发生运行时强制转换,并且将在放置行上失败(如预期的那样)。有人可以确认吗?
class TestMethodHolder {
String getValue(Map<String, Object> dataMap, String value) {
return (String)dataMap.get(value);
}
}
这是使用泛型的已知缺陷还是奇怪?那么在调用方法时使用<>表示法是不好的做法吗?
编辑:我正在使用默认的Oracle JDK 1.7_03。
上面另一个隐含的问题:原始getValue STILL的强制转换是否在运行时发生,但强制转换实际上是对对象的-
编译器是否足够聪明,可以完全消除这种强制转换?这可能解释了人们在运行ClassCastException时会注意到的区别。
编译器依赖于类型安全性进行假设并进行转换/优化。不幸的是,类型安全性可以通过未经检查的强制转换来破坏。如果您的程序包含不正确的未经检查的强制转换,则不清楚编译器应该做什么。理想情况下,它应在未检查的强制转换的确切点进行运行时检查,在您的示例中Object
为T
。但是由于擦除,这是不可能的,而这并不是类型系统的一部分。
在示例中的其他任何地方,类型都是健全的,因此编译器可以假定getValue()
确实返回a
String
,无需再次检查。但是进行检查也是合法的,就像Eclipse编译器所做的那样(可能是因为它将返回值分配给String
本地temp变量)。
因此,有个坏消息是,如果您的程序包含不正确的未经检查的强制转换,则其行为是不确定的…。因此,请通过严格的推理确保所有未经检查的强制转换都是正确的。
一个好的做法是检查所有未选中的强制类型转换,以便您可以合法地取消选中未选中的警告。例如
<T> T getValue(Map<String, Object> dataMap, String value, Class<T> type)
{
Object value = dataMap.get(value);
if(value!=null && !type.isInstance(value)) // check!
throw new ClassCastException();
@SuppressWarning("unchecked")
T t = (T)value; // this is safe, because we've just checked
return t;
}
看到我对类似问题的回答:Java中的惰性类转换?
问题内容: 注意:这是从Comparable和Comparator合约衍生出来的,涉及null 该代码可以在Eclipse(20090920-1017)中编译并正常运行 但是它不能在上编译javac 1.6.0_17。这是错误消息: 有人可以解释为什么差异吗?这是一个错误吗?如果是这样,谁有错误? 问题答案: 这是一个已确认的错误:错误ID 6468354。这是相关的摘录: 此问题是由以下事实引起
问题内容: 我不得不发现我的项目中有Java代码,该代码可以在Eclipse中编译并正常运行,但是会在javac中引发编译错误。 一个完整的代码段: javac中的编译返回: 现在,此错误阻止在Maven中构建项目。由于Eclipse编译器具有更高的容忍度,因此我现在不得不假设代码段的定义和用法如上所述,静态方法不是有效的Java吗? 问题答案: 似乎Sun的1.6 JDK无法推断正确的类型。以下
我尝试执行命令python,但在code的字符串上失败。为什么? C:\users\legion\downloads\meterrhyme-master>python-m transcrypt-b-m-n mr_index.py transcrypt(TM)Python to JavaScript Small Sane子集Transpiler version3.7.16版权所有(C)Geatec工
我对龙目岛或月食有问题,不确定是哪一个。我有一个Spring Boot maven项目,我正在使用Lombok。我在pom中添加了这个。xml文件,我使用了用于eclipse的lombok安装。 发生的事情是,我可以对项目进行和以及maven更新,一切都按预期构建。一旦我去运行项目,错误就开始出现,我得到错误,例如: 在运行项目时,有什么事情可以让龙目岛脱颖而出吗?! 我正在运行Eclipse O
我的构建服务器安装了Open JDK 8,我的正式服安装了oracle JRE 8。是否有可能在开放的JDK中编译代码并在Oracle JRE 8中部署工件?
当我使用以下命令运行下面的代码时 spark-提交prepiadstream_sample.py--主本地[3]--名称prepiadstream_sample--名称-执行器5--执行器-内存5G--驱动程序-内存5G 虽然我在Spark submit本地运行了配置,但我发现在代码中打印出的配置以客户端的身份返回部署模式,所以Spark不应该使用coniguration命令行