为什么将一个非常大的 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…
方法用于绝对值、加法、减法、递增、乘法、取反法和减法。
我在 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…
方法用于绝对值、加法、减法、递增、乘法、取反法和减法。