tl; dr
有什么区别吗…… int x = 100L; 与long x = 100;
是。 有很大的不同。
第一个不会编译,也不会运行。 您不能将64位long填充为32位int 。
第二个与第一个相反,第二个是扩展 32位int基本整数文字,同时将其分配给64位long基本整数变量。
细节
其他答案中有很多错误信息。
32位和64位整数基元
上面看到的L表示“ 64位 int整数基元 ”,而在整数文字中不存在L表示“ 32位 int整数基元”。
以下行无法编译。 您试图将64位long原始文字放入32位int变量中。 方钉,圆孔。 编译器的工作之一就是停止这种废话。
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.
原始而非对象
请注意,与在此页面上看到的其他答案相反,以上代码没有对象,只有基元 。
从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位整数的这种转换在技术上被称为Widening 。
包括我在内的某些人认为使用依赖于自动扩展的文字形式的此类代码是不好的形式。 您作为程序员的意图是模棱两可的。 因此,我将使用附加的L来编写该代码,例如long x = 100L ; 。 但是有些人会认为这个职位不必要地担心无关紧要的事情。
铸件
与其他答案相反,上面的代码中没有 强制转换 。
这是强制转换的示例。 我们从一个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位的值适合一百,因此被切除的高32位的集合全为零。 因此在这种情况下没有损坏。 但在这种情况下,此代码也是毫无意义的,不应在实际工作中完成。 的确,在实际工作中,只有很少(如果有的话)有生产性的理由可以通过强制转换来剥离64位整数的一半。
用Math.toIntExact缩小
强制转换的更好替代方法是调用Math.toIntExact 。 您将long int传递给此方法,它返回一个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支持自动装箱 。 为方便起见,在大多数情况下,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`.
同样,在课题中看到的代码与类/对象无关 。 除了其他不正确的答案引发了对象和自动装箱问题之外,本答案的这一部分将是无关紧要的。