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

Luc*_*cas 0 java generics updatemodel jsf-2

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

    private Set<Long> applicationIds;
Run Code Online (Sandbox Code Playgroud)

然后我像这样填充它:

public void setApplicationIds( Set<Long> applicationIds ) {
    this.applicationIds = new TreeSet<Long>( applicationIds );
    this.applications = null;
}
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用它:

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

我最终得到了这个:

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)
Run Code Online (Sandbox Code Playgroud)

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

                if ( applicationIds.contains( Long.valueOf( application.getId() ) ) ) {
Run Code Online (Sandbox Code Playgroud)

也许我错过了一些东西,但如果声明是,Set<Long>并且我正在调用contains传递Long.valueOf值的方法,我怎么能得到这个异常?

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

--------------编辑-----------------

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

public void setSelectedValues(Set<Long> 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;
}
Run Code Online (Sandbox Code Playgroud)

绑定到此组件:

<p:selectManyCheckbox id="numbers"
   value="#{controller.selectedValues}" layout="pageDirection">
  <f:selectItems value="#{controller.availableValues}" />
</p:selectManyCheckbox>
Run Code Online (Sandbox Code Playgroud)

将此内容写入日志:

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'
Run Code Online (Sandbox Code Playgroud)

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

作为旁注,我使用Java 7在Tomcat 7上对此进行了测试,并且ClassCastException消失了,但是,该contains方法始终false按预期返回.

--------------编辑2 -----------------

我发现我的组件绑定正确的方式回答这里.

--------------编辑3 -----------------

这里是问题的一个更好的解释.

Thi*_*ilo 5

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

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

看起来你Set<Long>实际上至少包含一个字符串.Set来自何处?

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

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

  • +1检查调用`setApplicationIds()`的人. (4认同)