Java 中的长文字

Long Literals in Java

因此通读文档,它指出如果您声明一个末尾带有 L 的 int 文字,它会将其读取为 long。这是我的问题:这与仅将类型命名为 long 开始之间有什么区别吗?例如:

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

同样的事情?

我不确定是否可以编译,因为您使用的是原始数据类型,但是如果您使用数字对象,请小心,因为 100L 是一个长对象,并且您正在将其分配给一个整数对象,并且分配是没有铸造,所以你需要小心。

注意原始类型和对象类型,知道何时进行转换。

long x = 100;

是一个100的整数,会被加宽成long,所有整数溢出的问题。

long x = 100L;

是一个没有加宽的初始化 long。

因此,当使用大于 Integer.MAX_VALUE 的数字时,您会看到不同之处。

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

如评论中所述,您不能将 long 文字分配给 int 变量。这被称为 narrowing primitive conversion(您可以在 JLS Chapter 5 阅读更多相关信息)。

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

然而,您可以 cast a long to an int (eg. int a=(int)1000L;) 并且编译器会很好,因为您现在应该知道那里可能会发生数据丢失。

tl;博士

is there any difference … int x = 100L; versus long x = 100;

是的。有很大的不同。

  • 第一个不会编译,也不会运行。您不能将 64 位 long 塞入 32 位 int
  • 第二个与第一个相反,加宽 32 位 int 原始整数文字,同时分配给 64 位 long原始整型变量。

详情

其他答案中有很多错误信息。

32 位与 64 位整数原语

上面看到的L的意思是“64-bit int integer primitive” whereas the absence of a L in an integer literal means “32-bit int integer primitive”。

下一行编译失败。您正在尝试将 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.

Error … incompatible types: possible lossy conversion from long to 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 用零填充额外的三十二位,所以实际上你最终得到了相同的数字。

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。有关技术讨论,请参阅 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.

在这个具体的例子中,没有问题,因为值100适合低32位,所以被切除的高32位集合都是零。所以在这种情况下没有损坏。但同样在这种情况下,这段代码毫无意义,不应该在实际工作中完成。事实上,在实际工作中,你很少(如果有的话)有一个有效的理由通过强制转换来削减 64 位整数的一半位。

缩小 Math.toIntExact

一个更好的转换替代方法是调用 Math.toIntExact. You pass a long primitive to this method, and it returns an int, the result of narrowing the 64-bit integer to 32-bit integer. The advantage over casting is that an 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表示Longclass而不是long原始。我不会在这里解释区别,只是说我希望 Java 从未明确使用原语,而是坚持只使用 classes。事实上,在遥远的未来,Java 的一个版本极有可能做到这一点(隐藏基元的存在)。

但是此时此地,classes/objects 和原语之间存在区别。为了帮助消除这种区别,Java 支持 auto-boxing。为方便起见,在大多数情况下,Java 编译器和 运行time 可以检测您的代码何时将原语分配给预期对象的位置,反之亦然。

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 ) ;

And 在逻辑上等同于以下内容,但从技术上讲,下一行会失败(编译器错误),因为字符串中不需要 L,因为假定字符串包含 a 的数字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`. 

同样,问题中看到的代码没有涉及classes/objects。除了其他不正确的答案提出了对象和自动装箱的问题之外,本答案的这一部分是无关紧要的。