public Long getId()
{
Some code ...
TypedQuery<Long> query = entityManager.createQuery(sQuery, Long.class);
return query.getSingleResult();
}
从此代码中,我从ClassCastException
到Integer
获得Long
。我在调试器中检查了query.getSingleResult();
,然后我查了Integer
5.
如果我将代码更改为query.getSingleResult().longValue();
,它仍然无效。我得到了同样的例外。但如果我使用
Number tmp = query.getSingleResult();
return tmp.longValue();
它有效。我的问题是为什么第一个解决方案不起作用? Surley我可以更改我的查询,但我只想知道为什么secound有效而第一个没有。
随意更改我的问题标题。提前谢谢!
答案 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();
此代码成功,因为Integer
是Number
。
因此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)
只是Object
,Object
没有方法longValue
。使用该方法,强制类型的不是最不具体的类型,而只是Long
。因此第二行变为
((Long) list.get(0)).longValue();
并抛出ClassCastException
。
另一方面,如果你做了
Number a = list.get(0);
a.longValue();
由于Long
已经有Number
方法,因此无需使用隐形广播来输入longValue
。此版本不会引发异常。
答案 2 :(得分:0)