可能重复:
ClassCastException when calling TreeSet<Long>.contains( Long.valueOf( someLongValue ) )
请查看问题的屏幕截图:
类似集cylinderIds
中的条目似乎突然出现String
类型 - 但这是怎么发生的?
bean在JSF页面中使用,但我一直认为Java中的类型系统应该阻止这个......任何想法在这里出了什么问题?
在Windows 7上使用1.7.0_06 64位,该应用程序在同一Java版本的JBoss 7.1.0中运行。
答案 0 :(得分:2)
这不完全是Java的错。通用类型信息在运行时丢失。 Java / JSF / EL在编译期间不运行,但在运行时期间运行。它在运行时期间看到的只是Set
,而不是Set<Long>
。
当JSF将提交的输入值设置为bean属性时,它首先将它们检索为String
,因为它是request.getParameter()
的默认返回类型,JSF正在使用它来获取请求参数。只要没有指定转换器,JSF就会通过反射在String
中设置未转换的提交的Set
值。这基本上就是“幕后”发生的事情:
package com.stackoverflow.q14521882;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class Test {
private Set<Long> set = new HashSet<Long>();
public static void main(String[] args) throws Exception {
Test test = new Test();
Field field = test.getClass().getDeclaredField("set");
Object object = field.get(test);
if (object instanceof Collection) {
((Collection) object).add("string");
}
System.out.println(test.set.iterator().next().getClass()); // CCE!
}
}
当您使用Long[]
代替Set<Long>
时,它会有效,但鉴于它首先是Set
,您只想保留唯一值Long[]
因此,1}}可能不是一种选择。为了解决这个问题,您需要在输入组件中明确指定Converter
。您可以使用JSF内置LongConverter
,其转换器ID为javax.faces.Long
:
<h:selectManyListbox ... converter="javax.faces.Long">
答案 1 :(得分:1)
第一个问题是,每次进入Iterator
时,您都会要求新的while
。第二个问题是Iterator
是通用的,所以你最好做这样的事情:
Iterator<Long> cylinderIter = cylinderIds.iterator();
while(cylinderIter.hasNext()) {
cylinderIter.next() // ...
// do something
}
第三个问题是,我无法看到您填充Set
的位置。如果您向我们展示代码,我可以为您提供更多帮助。
答案 2 :(得分:0)
如果没有看到您的代码,我可以回答有些内容正在改变您的代码类型:
泛型是通过类型擦除实现的:泛型类型信息是 仅在编译时出现,之后它被删除 编译器。这种方法的主要优点是它提供了 通用代码与使用的遗留代码之间的完全互操作性 非参数化类型(技术上称为原始类型)。 主要缺点是参数类型信息在运行时不可用,并且自动生成的强制转换可能会失败 与不良遗留代码进行互操作时。但是, 一种实现通用的运行时类型安全性的方法 即使与不良遗留代码进行互操作,也可以收集。
oracle文档的generics文章更好地解释了你。
尝试使用此代码查看问题发生的时间:
Set<Long> s = Collections.checkedSet(new HashSet<Long>(), Long.class);