调用TreeSet 时的ClassCastException .contains(Long.valueOf(someLongValue))

我很难过。 我这样宣布我的一套:

private Set applicationIds; 

然后我像这样填充它:

 public void setApplicationIds( Set applicationIds ) { this.applicationIds = new TreeSet( applicationIds ); this.applications = null; } 

然后我尝试使用它:

 public List getApplications() { if ( applications == null ) { applications = new ArrayList(); if ( applicationIds != null ) { for ( Application application : availableApplications ) { if ( applicationIds.contains( Long.valueOf( application.getId() ) ) ) { applications.add( application ); } } } } return applications; } 

我最终得到了这个:

 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long at java.lang.Long.compareTo(Long.java:50) at java.util.TreeMap.getEntry(TreeMap.java:346) at java.util.TreeMap.containsKey(TreeMap.java:227) at java.util.TreeSet.contains(TreeSet.java:234) at org.mitre.asias.pf.pnp.viewmodel.Subscription.getApplications(Subscription.java:84) 

导致exception的行(来自堆栈跟踪的第84行)是这样的:

  if ( applicationIds.contains( Long.valueOf( application.getId() ) ) ) { 

也许我遗漏了一些东西,但是如果声明是Set并且我调用的是传递Long.valueOf值的contains方法,我怎么能得到这个exception?

这是JSF应用程序的模型bean。 我正在使用Java 6,Tomcat 6.0.32,mojarra 2.1.14,但这些都不应该真正重要,因为generics应该防止这种问题编译时…

————–编辑—————–

它实际上是JSF ……我用这个setter汇总了一个超简化的例子:

 public void setSelectedValues(Set selectedValues) { this.selectedValues = selectedValues; if (logger.isTraceEnabled()) { StringBuilder message = new StringBuilder("Selected values:"); for (Object value : selectedValues) { message.append("\n\t'").append(value.getClass().getName()) .append("': '").append(value.toString()).append("'"); } logger.trace(message.toString()); } this.selections = null; } 

绑定到此组件:

 

将其写入日志:

 15:45:16.887 [http-bio-8080-exec-9] TRACE com.pastdev.learn.debug.Controller - Selected values: 'java.lang.String': '1' 'java.lang.String': '5' 

所以,简单的答案是正确的(谢谢@PaulTomblin强调这一点)。 使用包含StringSet调用setter。 那么现在,转换的最佳流程是什么? 我是否需要遍历将每个值转换为Long的列表?

作为旁注,我使用Java 7在Tomcat 7上测试了这个并且ClassCastException消失了,但是, contains方法总是返回false因为应该是预期的。

————–编辑2 —————–

我找到了一个答案,正确的方法来绑定我的组件。

————–编辑3 —————–

这是对问题的更好解释。

也许我遗漏了一些东西,但如果声明是Set并且我调用的是传入Long.valueOf值的contains方法,我怎么能得到这个exception?

请注意,在Java中,generics类型注释只是编译器的提示,并且在运行时没有任何影响,因此可能在运行时违反这些约束(但在某处会有编译器警告)。

看起来你的Set实际上至少包含一个String。 Set来自何处?

因为generics应该防止这种问题编译时间

是的,代码中应该有关于缺少generics类型或未经检查的强制转换的警告。 这只是一个警告,因为generics是可选的。 在您使用它们的地方,这将是一个错误。

好的@Lucas我只是尝试使用您在问题中发布的代码使用快速而脏的代码,它运行正常。 您可能需要再次检查您的Application类。

 package javaapplication2; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; public class JavaApplication2 { private static Set applicationIds; private List applications; private static final List availableApplications = new ArrayList<>(); public static void main(String[] args) { JavaApplication2 proj = new JavaApplication2(); for (int i = 1; i <= 11; i++) { Application application = new Application(); application.setId(i); availableApplications.add(application); } Set applicationIds1 = new TreeSet<>(); applicationIds1.add(11L); applicationIds1.add(12L); applicationIds1.add(13L); proj.setApplicationIds(applicationIds1); for (Application appl : proj.getApplications()) { System.out.println(appl.getId()); } } public void setApplicationIds(Set applicationIds) { this.applicationIds = new TreeSet(applicationIds); this.applications = null; } public List getApplications() { if (applications == null) { applications = new ArrayList(); if (applicationIds != null) { for (Application application : availableApplications) { if (applicationIds.contains(Long.valueOf(application.getId()))) { applications.add(application); } } } } return applications; } 

}

和:

 package javaapplication2; class Application { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } }