Java中原始整数类型的行为不一致 [英] Inconsistent behaviour of primitive integer types in Java

查看:115
本文介绍了Java中原始整数类型的行为不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人能像我五岁时一样向我解释为什么为什么用Java表示整数的四个原始类型中的两个会有不同的行为吗? AFAIK的全部四个都是带符号的,并且它们都使用最高有效位作为符号位,那么为什么字节和短整型的行为正常,而整型和长整型的行为又奇怪呢?解释这一点的oracle文档片段将是完美的.

Can someone explain to me like I'm five why I get different behaviour for two of four primitive types representing integers in Java? AFAIK all four are signed and they all use the most significant bit as a sign bit, so why do byte and short behave normally, and int and long act, well, strange? The fragment of oracle docs explaining this would be perfect.

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'?

我正在使用Windows的Oracle Java SE 1.7.操作系统是Windows 7 Professional SP1

I'm using Oracle's Java SE 1.7 for Windows. OS is 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. Shift运算符可以很好地处理字节,短裤和整数,但是对于多头来说,我警告它是一种故障.


EDIT, after reading all the answers and tuning my code.
So, to sum up, the only way I found to get expected values is the use of BigInteger. Shift operator works well for bytes, shorts and ints, but when it comes to longs, I cought it on one malfunction.

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,一切都可以完美运行

With BigInteger everything works flawlessly

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 talks about the behavior of the narrowing primitive conversion used by the cast

否则,以下两种情况之一必须为真:

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

该值必须太小(负值较大或负无穷大),并且第一步的结果是int或long类型的最小可表示值.

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.

该值必须太大(正值较大或正无穷大),第一步的结果是 int或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的原因.

That is why (int) (Math.pow(2, 32)); becomes Integer.MAX_VALUE and (long) (Math.pow(2, 64)) becomes Long.MAX_VALUE.

这篇关于Java中原始整数类型的行为不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆