Java中的长整型字面量

6

阅读文档后,发现如果在int字面量后面加上L,它会将其视为long类型。我的问题是:这种方式和一开始就声明long类型有什么区别吗?例如:

int x = 100L;
VS.
long x = 100;

相同的事情?

3
int x = 100L 无法编译 - 您需要将其声明为长整型类型。我认为您可能想询问 long x = 100;long x = 100L; 的区别。 - takendarkk
long a=100Llong a=100结果将是相同的。 - PM 77-1
1
以下代码无法编译 long l = 123123123123123123123123123123123;,因为 123123123123123123123123123123123 无法放入 int 中。但是如果在末尾添加 L,就可以通过编译。 - Ivan
3个回答

10

简短概括

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使用零填充额外的三十二位,因此最终您得到相同的数字。

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扩展基本转换
一些人,包括我在内,认为使用依赖于自动扩展的文字代码形式不好。作为程序员,您的意图是含糊不清的。因此,我会使用附加的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.

在这个特定的例子中,没有问题,因为100的值符合较低的32位,所以被删除的更高的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.
}

对象

由于其他答案错误地提到了对象和自动装箱的主题,我会稍微提一下。

以大写字母L开头的单词Long表示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. 

只需从该字符串输入中删除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`. 

再次强调,问题中的代码与类/对象没有任何关系。这个答案的这一部分可能与此无关,只是因为其他不正确的答案涉及了对象和自动装箱。


2
long x = 100;

这是一个整数100,将被扩展为长整型,所有整数溢出的问题都会被解决。

long x = 100L;

这是一个未扩展的长整型。

因此,当使用大于Integer.MAX_VALUE的数字时,您将看到差异。

long x = 2147483648L; // will be the value that you expect it to be
long y = 2147483648;  // will not compile

3
100 不会被强制转换为 long,而是会进行扩展。你可以使用强制转换来进行扩展转换,或者它也可以由编译器隐式完成(在这里)。但是,castingJLS 15.16 Cast Expressions)和 wideningJLS 5.1.2 Widening Primitive Conversion)是两个不同的概念,需要区分开来,不能混淆。 - Andreas
int 扩展为 long 据我所知并没有“整数溢出问题”,请解释。 - Basil Bourque

1

正如评论中所述,您不能将一个long字面值赋给一个int变量。这被称为缩小原始转换(您可以在JLS第5章中了解更多信息)。

long将始终使用64位来表示其值,而int将使用32位。因此,将long值分配给int,您将失去32位数据,因为变量中没有空间。编译器将标记此为错误,以保护您免受潜在的数据丢失。

但是,您可以将long强制转换为int(例如:int a =(int)1000L;),编译器会接受它,因为您现在应该知道可能会发生数据丢失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接