为什么将一个非常大的 long 数字转换为 int 会给我们一个奇怪的输出 (Java)?

Why casting a very large long number to int gives us a strange output (Java)?

我在 Java 练习了一些转换,我遇到了一个我在任何地方都找不到任何答案的情况。有很多类似的问题和答案,但是 none 给了我一个针对这个特殊情况的解释。

当我做类似

的事情时
    long l = 165787121844687L;
    int i = (int) l;

    System.out.println("long: " + l);
    System.out.println("after casting to int: " + i);

输出为

long: 165787121844687
after casting to int: 1384219087

这个结果对我来说很有趣。

我知道long类型是64位整数,int类型是32位整数。我还知道,当我们将较大的类型转换为较小的类型时,我们可能会丢失信息。我知道有一个 Math.toIntExact() 方法非常有用。

但是这个“1384219087”输出的解释是什么?有数据丢失,但为什么是这个数字? “165787121844687”如何变成“1384219087”?为什么代码甚至可以编译?

就是这样。谢谢!

如果将这两个数字转换成十六进制,你会得到

96C8528181CF
528181CF

看看这里发生了什么?

165787121844687L 十六进制表示法 = 0000 96C8 5281 81CF

1384219087 十六进制 = 5281 81CF

所以演员表按预期截断了前 32 位。

                        32-bits 
                        deleted 
                       ▼▼▼▼ ▼▼▼▼
165_787_121_844_687L = 0000 96C8 5281 81CF  ➣  1_384_219_087
    64-bit long                  ▲▲▲▲ ▲▲▲▲      32-bit int 
                                  32-bits 
                                 remaining

是正确的,应该接受。这是一些附加信息和解决方法。

Java 规范是这样说的

Why does the code even compile?

当您在 Java 中转换数字基元时,您对结果负责,包括信息丢失的风险。

为什么?因为 Java 规范是这么说的。总是最好阅读文档。靠直觉编程是有风险的。

参见Java Language Specification, section 5.1.3. Narrowing Primitive Conversion。引用(强调我的):

A narrowing primitive conversion may lose information

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

Math#…Exact…

当您希望在 conversion from a long to a short, use the Math 方法期间收到数据丢失警报以确保准确性时。如果操作溢出,则抛出执行。您可以捕获该异常。

try 
{
   int i = Math.toIntExact( 165_787_121_844_687L ) ;  // Convert from a `long` to an `int`. 
} 
catch ( ArithmeticException e ) 
{ 
    // … handle conversion operation overflowing an `int` …
}

您会发现类似的 Math#…Exact… 方法用于绝对值、加法、减法、递增、乘法、取反法和减法。