Integer.longValue() 如果没有先分配给 Number 会抛出异常
Integer.longValue() does throw an Exception if not assigned to Number first
public Long getId()
{
Some code ...
TypedQuery<Long> query = entityManager.createQuery(sQuery, Long.class);
return query.getSingleResult();
}
从这段代码中,我得到了从 Integer
到 Long
的 ClassCastException
。我在调试器中检查了 query.getSingleResult();
并添加了 Integer
5.
如果我将代码更改为 query.getSingleResult().longValue();
,它仍然不起作用。我得到同样的例外。但是如果我使用
Number tmp = query.getSingleResult();
return tmp.longValue();
有效。我的问题是 为什么第一个解决方案不起作用? Surley 我可以更改我的查询,但我只想知道为什么第二个解决方案有效而第一个无效。
请随意更改我的问题的标题。提前致谢!
您的查询实际上 returns 一个 Integer
但您通过调用 entityManager.createQuery(sQuery, Long.class)
.
假装它 returns 一个 Long
现在当你执行
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()
抛出异常,而是之前发生的转换。
createQuery
的规范说:
The select list of the query must contain only a single item, which must be assignable to the type specified by the resultClass argument.
因此您遇到了问题,因为 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
。此版本不抛出异常。
第一种方法不可行,因为你使用了错误的方法来进行此转换。这个Class的树是这样的:
正确的 Cast 方法是先将 Integer 转换为 Number,然后调用 longValue() 方法转换为 Long。
第二种方法有效,因为您按照正确的步骤投射了这两种类型的数字。
看看下面的打印。编译器不喜欢这种强制转换方式。不仅适用于 Long,也适用于 BigDecimal 以及其他数字
public Long getId()
{
Some code ...
TypedQuery<Long> query = entityManager.createQuery(sQuery, Long.class);
return query.getSingleResult();
}
从这段代码中,我得到了从 Integer
到 Long
的 ClassCastException
。我在调试器中检查了 query.getSingleResult();
并添加了 Integer
5.
如果我将代码更改为 query.getSingleResult().longValue();
,它仍然不起作用。我得到同样的例外。但是如果我使用
Number tmp = query.getSingleResult();
return tmp.longValue();
有效。我的问题是 为什么第一个解决方案不起作用? Surley 我可以更改我的查询,但我只想知道为什么第二个解决方案有效而第一个无效。
请随意更改我的问题的标题。提前致谢!
您的查询实际上 returns 一个 Integer
但您通过调用 entityManager.createQuery(sQuery, Long.class)
.
Long
现在当你执行
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()
抛出异常,而是之前发生的转换。
createQuery
的规范说:
The select list of the query must contain only a single item, which must be assignable to the type specified by the resultClass argument.
因此您遇到了问题,因为 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
。此版本不抛出异常。
第一种方法不可行,因为你使用了错误的方法来进行此转换。这个Class的树是这样的:
正确的 Cast 方法是先将 Integer 转换为 Number,然后调用 longValue() 方法转换为 Long。
第二种方法有效,因为您按照正确的步骤投射了这两种类型的数字。
看看下面的打印。编译器不喜欢这种强制转换方式。不仅适用于 Long,也适用于 BigDecimal 以及其他数字