如果未分配给Number

时间:2015-11-04 11:41:06

标签: java jpa eclipselink

public Long getId()
{
    Some code ...

    TypedQuery<Long> query = entityManager.createQuery(sQuery, Long.class);
    return query.getSingleResult();
}

从此代码中,我从ClassCastExceptionInteger获得Long。我在调试器中检查了query.getSingleResult();,然后我查了Integer 5.

如果我将代码更改为query.getSingleResult().longValue();,它仍然无效。我得到了同样的例外。但如果我使用

Number tmp = query.getSingleResult();
return tmp.longValue();

它有效。我的问题是为什么第一个解决方案不起作用? Surley我可以更改我的查询,但我只想知道为什么secound有效而第一个没有。

随意更改我的问题标题。提前谢谢!

3 个答案:

答案 0 :(得分:7)

您的查询实际上会返回Integer,但您通过调用Long假装它返回entityManager.createQuery(sQuery, Long.class)

现在执行

query.getSingleResult()
query.getSingleResult().longValue()

由于您的泛型声明,编译器会将强制转换插入到Long中。因此,这实际上是执行的:

(Long)query.getSingleResult()
((Long)query.getSingleResult()).longValue()

并抛出ClassCastException,因为Integer不是Long

致电时

Number tmp = query.getSingleResult();

它实际上执行

Number tmp = (Number)query.getSingleResult();

此代码成功,因为IntegerNumber

因此longValue()不会抛出异常,而是抛出之前的演员。

答案 1 :(得分:0)

createQuery的规范说:

  

查询的选择列表必须只包含一个项目,该项目必须可以分配给resultClass参数指定的类型。

因此Integer无法分配给Long,因此您遇到了问题。然而,有趣的是要考虑为什么一个版本抛出异常而另一个版本不抛出异常。

我将使用更熟悉的类来解释使用Number类型的临时变量之间的区别。

此示例抛出ClassCastException

 List<Long> list = (List<Long>) (List) Collections.singletonList(5); // Very dodgy.
 list.get(0).longValue();

原因是泛型只是一个编译时功能,必要时会插入不可见的强制转换。实际上,list.get(0)只是ObjectObject没有方法longValue。使用该方法,强制类型的不是最不具体的类型,而只是Long。因此第二行变为

((Long) list.get(0)).longValue();

并抛出ClassCastException

另一方面,如果你做了

Number a = list.get(0);
a.longValue();

由于Long已经有Number方法,因此无需使用隐形广播来输入longValue。此版本不会引发异常。

答案 2 :(得分:0)

第一种方式不起作用,因为你用错误的方式进行演员表演。这个类的树是这样的:

enter image description here

执行此操作的正确方法是首先将Integer转换为Number,然后转换为Long调用longValue()方法。

第二种方式有效,因为您按照正确的步骤来投射这两种类型的数字。

查看以下内容。编译器不喜欢这种强制转换方式。不仅仅是Long,BigDecimal以及其他数字

enter image description here