【问题标题】:Why initialization of new Long Wrapper with int literal is valid?为什么用 int 字面量初始化新的 Long Wrapper 是有效的?
【发布时间】:2017-07-23 08:19:20
【问题描述】:
查看Long的Java Doc,它只有两个构造函数:
1) primitive long as param --> new Long(10L);
2) String as param --> new Long("23");
但这行得通
新长(23);
但如果字面量大于 int MAX VALUE (2147483647),则 L 后缀成为强制性的,因此:(
new Long(2147483648) 现在需要在值后面加一个 L
但是:
new Long(Integer.MAX_VALUE + 1) 没问题
谁能解释一下?
【问题讨论】:
标签:
java
initialization
long-integer
【解决方案1】:
您问题的第一部分很简单:在需要long 的地方传递int 是允许的,因为任何可以表示为int 的数字也可以表示为long。这就是所谓的加宽转换。
第二部分,关于new Long(Integer.MAX_VALUE + 1),比较棘手。尽管这里也发生了扩大转换,但它并不像人们想象的那样:如果你运行这个程序
Long x = new Long(Integer.MAX_VALUE + 1);
System.out.println(x);
你得到-2147483648,而不是预期的2147483648,因为int在加法时溢出(demo)。
编译器不够聪明,无法在执行加法之前将部分表达式提升为long。加法运算完成后发生加宽转换,加法运算结果溢出。
【解决方案2】:
你可以在javadocs找到答案:
在 strictfp 表达式(第 15.4 节)中,从整数类型到另一种整数类型或从 float 到 double 的扩展原语转换根本不会丢失任何信息;数值被完全保留。
整数值23 可以转换为long 23L,而不会丢失任何信息。因此,通过加宽原始转换的使用,JVM 将其隐式转换为23L。
所以当你打电话时
new Long(23)
变成了
new Long(23L)
【解决方案3】:
当我们写 new Long(23) 时,你可以把它想象成如下发生的事情:
int i = 23;
long l = i; // widening primitive conversion
Long newLong = new Long(l);
根据 JLS 5.1.2 允许扩大转换,因此没有问题。
当我们尝试改用 new Long(2147483648) 时,第一步本身会失败,因为该值超出了 int 可以容纳的值
int i = 2147483648; // doesn't fit in int
当我们尝试new Long(Integer.MAX_VALUE + 1) 时,您可以将其视为如下发生的事情:
int i = Integer.MAX_VALUE + 1; // This gives the INTEGER.MIN_VALUE -2147483648
long l = i ; // widening primitive conversion
Long newLong = new Long(l);
所以,这是允许的。希望这会有所帮助。
【解决方案4】:
区别在于是否使用文字。
通过使用文字,
long1 = new Long(2147483648)
代码不会编译,因为编译器会再次检查文字的有效性,接收文字值的变量的类型和2147483648 超出了int 的范围。
所以编译器发出一个错误。
它适用于任何文字。
作为compiler expects to have a specific type as value of the literals,它会进行检查:
字面量的类型确定如下:
以 L 或 l 结尾的整型文字(第 3.10.1 节)的类型是 long
(§4.2.1)。
任何其他整数文字的类型都是 int(第 4.2.1 节)。
...
通过使用计算:
long1 = new Long(Integer.MAX_VALUE + 1);
编译器不会检查 Long 参数构造函数的大小是否在 int 范围内。
这不是文字声明。
在运行时,会发生 int 到 long 的扩展原语转换。
它产生了一个int 和Integer.MAX_VALUE + 1,即-2147483648(int 的溢出),它被转换为long 值。