java - Java 中原始整数类型的不一致行为

标签 java primitive-types scjp

有人能像我五岁那样向我解释为什么我对 Java 中表示整数的四种原始类型中的两种有不同的行为吗? AFAIK 这四个都是有符号的,它们都使用最高有效位作为符号位,那么为什么 byte 和 short 表现正常,而 int 和 long 表现得很好,很奇怪?解释这一点的 oracle 文档片段将是完美的。

byte a = (byte) (Math.pow(2, 7)-1); //127 - as expected
short b = (short) (Math.pow(2, 15)-1); //32767 - as expected
int c = (int) (Math.pow(2, 31)-1); //2147483647 - as expected
long d = (long) (Math.pow(2, 63)-1); //9223372036854775807 - as expected

a = (byte) (Math.pow(2, 7)); //-128 - as expected
b = (short) (Math.pow(2, 15)); //-32768 - as expected
c = (int) (Math.pow(2, 31)); //2147483647 - why not '-2147483648'?
d = (long) (Math.pow(2, 63)); //9223372036854775807 - why not '-9223372036854775808'?

a = (byte) (Math.pow(2, 8)); //0 - as expected
b = (short) (Math.pow(2, 16)); //0 - as expected
c = (int) (Math.pow(2, 32)); //2147483647 - why not '0'?
d = (long) (Math.pow(2, 64)); //9223372036854775807 - why not '0'?

我正在使用 Oracle 的 Java SE 1.7 for Windows。操作系统为 Windows 7 Professional SP1

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

编辑,在阅读所有答案并调整我的代码后。
因此,总而言之,我发现获得预期值的唯一方法是使用 BigInteger。移位运算符适用于字节、短整型和整数,但当涉及到长整型时,我会因为一个故障而忽略它。

byte a = (byte) ((1l << 7) - 1); //127 - as expected
short b = (short) ((1l << 15) - 1); //32767 - as expected
int c = (int) (1l << 31) - 1; //2147483647 - as expected
long d = (1l << 63) - 1; //9223372036854775807 - as expected

a = (byte) (1l << 7); //-128 - as expected
b = (short) (1l << 15); //-32768 - as expected
c = (int) 1l << 31; //-2147483648 - as expected
d = 1l << 63; //-9223372036854775808 - as expected

a = (byte) (1l << 8); //0 - as expected
b = (short) (1l << 16); //0 - as expected
c = (int) (1l << 32); //0 - as expected
d = 1l << 64; //1 instead of 0, probably because of the word length limitation      

有了 BigInteger,一切都完美无缺

byte a = (byte) (new BigInteger("2").pow(7).longValue() - 1); //127 - as expected
short b = (short) (new BigInteger("2").pow(15).longValue() - 1); //32767 - as expected
int c = (int) (new BigInteger("2").pow(31).longValue() - 1); //2147483647 - as expected
long d = (new BigInteger("2").pow(63).longValue() - 1); //9223372036854775807 - as expected

a = (byte) (new BigInteger("2").pow(7).longValue()); //-128 - as expected
b = (short) (new BigInteger("2").pow(15).longValue()); //-32768 - as expected
c = (int) new BigInteger("2").pow(31).longValue(); //-2147483648 - as expected
d = new BigInteger("2").pow(63).longValue(); //-9223372036854775808 - as expected

a = (byte) (new BigInteger("2").pow(8).longValue()); //0 - as expected
b = (short) (new BigInteger("2").pow(16).longValue()); //0 - as expected
c = (int) (new BigInteger("2").pow(32).longValue()); //0 - as expected
d = new BigInteger("2").pow(64).longValue(); //0 - as expected

感谢大家的大力帮助!

最佳答案

Section 5.1.3 of the JLS浅谈cast使用的narrowing primitive conversion的行为

Otherwise, one of the following two cases must be true:

The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of type int or long.

The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.

(强调我的)

这就是为什么 (int) (Math.pow(2, 32)); 变成了 Integer.MAX_VALUE(long) (Math.pow( 2, 64)) 变为 Long.MAX_VALUE

关于java - Java 中原始整数类型的不一致行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20434738/

相关文章:

c# - 为什么 C# 中的基本类型有自己的操作?

java - 如何将 Java 对象类型(如 Long 和 Integer)转换为原始类型(如 long 和 int)

Java继承方法问题

java - java中动态更新JSON文档

尝试通过 SMTP 发送电子邮件时出现 java.lang.NoClassDefFoundError (Java)

java - 数组上的if语句

java - 了解加入()

java - 多态性中的初始化 block

java - 是否可以在 Java Monkey Engine 中创建平坦地形?

java - 为什么java中的isActive()函数在windows中工作而在ubuntu中不起作用