因此,通读文档会指出,如果声明一个以L结尾的int常量,它将改为读取long值。这是我的问题:这与将类型命名为很长的名称之间有什么区别吗?例如:
int x = 100L;
VS.
long x = 100;
同一件事情?
最佳答案
tl; dr
有什么区别... int x = 100L;
与long x = 100;
是。有很大的不同。
long
塞入32位int
。 int
基本整数文字,同时分配给64位long
基本整数变量。 细节
其他答案中有很多错误信息。
32位和64位整数基元
上面看到的
L
表示“64-bit int
整数primitive”,而整数literal中不存在L
则表示“32-bit int
整数基元”。以下行无法编译。您正在尝试将64位
long
原语文字放入32位int
变量中。方钉,圆孔。 compiler的工作之一就是制止这种胡说八道。int x = 100L ; // BAD — compiler fails — Cannot place a 64-bit `long` `int` primitive in a 32-bit `int` variable.
错误…不兼容的类型:可能从long到int的有损转换
让我们通过删除
L
来更正该行,为32位int
变量分配32位int
文字。int x = 100 ; // 32-bit `int` integer primitive literal being stored in a 32-bit `int` integer variable. No problem, no issues.
原始对象,而非对象
请注意,与此页面上的其他答案相反,上面的代码没有对象,只有primitives。
从32位扩展到64位
在下一行中,您首先要创建一个带有“100”部分的32位
int
原语。然后将该32位int
原语分配给64位long
原语。 Java用零填充多余的32位,因此实际上您得到的是相同的数字。long x = 100 ; // 32-bit `int` integer primitive being stored in a 64-bit `long` integer primitive. The extra 32-bits are filled in with zeros automatically by Java.
正如Andreas在评论中指出的那样,这种从32位整数到64位整数的转换在技术上称为扩展。有关技术讨论,请参见JLS 5.1.2 Widening Primitive Conversion。
包括我在内的某些人认为使用依赖于自动扩展的文字的此类代码的形式很差。您作为程序员的意图是模棱两可的。因此,我将使用附加的
L
编写该代码,例如long x = 100L ;
。但是有些人会认为这个职位不必要地担心无关紧要的事情。铸件
与其他答案相反,上面的代码中没有casting。
这是强制转换的示例。我们从64位
long
原语开始。然后,当将其强制转换为int
原语时,放弃高32位。 (int)
告诉编译器“是的,我知道在砍掉我的64位中的32位时冒着数据丢失的风险,但是请继续并为此承担责任”。int x = (int) 100L ; // Start with a 64-bit `long` primitive literal, lop off 32 of the 64 bits, resulting in a 32-bit `int` primitive being assigned to a 32-bit primitive variable.
在此特定示例中,这没有问题,因为较低的32位的数值为100,因此,被切除的较高的32位的集合全为零。因此在这种情况下没有损坏。但在这种情况下,此代码也是毫无意义的,因此不应在实际工作中完成。确实,在实际工作中,只有很少(如果有的话)有生产性的理由可以通过强制转换来丢弃64位整数的一半。
用
Math.toIntExact
缩小强制转换的更好替代方法是调用
Math.toIntExact
。您将long
原语传递给此方法,然后返回int
,即将64位整数缩小为32位整数的结果。与强制转换相比的优势在于,如果发生溢出,将抛出 ArithmeticException
。因此,您将收到有关任何数据丢失的通知。try {
int x = java.lang.Math.toIntExact( 100L ) ;
} catch ( ArithmeticException e ) {
… // Handle data loss, the overflow in going from 64-bits to 32-bits.
}
对象
由于其他一些答案错误地提出了对象和自动装箱的主题,因此我将对此稍作提及。
前面带有大写
Long
的措辞L
表示Long
类,而不是long
原语。我不会在这里解释这种区别,只是说我希望Java从未明确使用基元,而是只限于类。实际上,在不久的将来,Java版本很可能做到这一点(隐藏原语的存在)。但是在这里和现在,类/对象和基元之间是有区别的。为了帮助消除这种区别,Java支持auto-boxing。为方便起见,在大多数情况下,Java编译器和运行时都可以检测代码何时将基元分配给期望对象的位置,反之亦然。
Long myLongObject = 100L ; // This works because Java automatically detects the primitive `long` being assigned to an object of class `Long`, and instantiates a `Long` object to hold that number value.
上面的那一行实际上被视为:
Long myLongObject = Long.valueOf( 100L ) ;
并且在逻辑上等效于以下内容,但是从技术上讲,下一行失败(编译器错误),因为在字符串中不需要
L
,因为假定该字符串包含64位整数的数字。换句话说,此输入字符串不是整数文字,因此L
是多余的,不允许使用。Long myLongObject = Long.valueOf( "100L" ) ; // Compiler error. The `L` is not allowed because it is redundant.
只需从该String输入中删除
L
即可,因为假定该输入代表一个64位数字。Long myLongObject = Long.valueOf( "100" ) ;
Java也将在执行自动装箱操作之前从32位
int
自动扩展。因此,以上各行实际上也与此相同。Long myLongObject = Long.valueOf( 100 ) ; // 32-bit `int` primitive literal automatically widened to a 64-bit `long`, then passed as argument to the `valueOf` method that takes only a `long`.
同样,在课题中看到的代码与类/对象无关。除了其他不正确的答案引发了对象和自动装箱问题之外,本答案的这一部分将是无关紧要的。