[英]Inconsistent behaviour of primitive integer types in Java
有人可以解釋一下,為什么我在Java中為表示整數的四種基本類型中的兩種獲得不同的行為? AFAIK全部四個都是簽名的,它們都使用最重要的位作為符號位,那么為什么字節和短行為正常,而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。 Shift運算符適用於字節,短路和整數,但是當涉及到longs時,我會在一次故障時使用它。
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
謝謝大家的幫助!
JLS的5.1.3節討論了演員使用的縮小基元轉換的行為
否則,以下兩種情況之一必須為真:
該值必須太小(大幅度或負無窮大的負值),第一步的結果是int或long類型的最小可表示值。
該值必須太大(大幅度或正無窮大的正值),第一步的結果是int或long類型的最大可表示值 。
(強調我的)
這就是為什么(int) (Math.pow(2, 32));
變為Integer.MAX_VALUE
和(long) (Math.pow(2, 64))
Long.MAX_VALUE
(long) (Math.pow(2, 64))
變為Long.MAX_VALUE
。
Math.pow()
返回一個double
,然后在轉換為整數類型時進行舍入。 在使它們溢出所需的精度下, double
顯然是圓形的。
指導:
public class PowTest {
public static void main(String[] argv) {
double powResult = Math.pow(2.0,31.0);
int powInt = (int) powResult;
long powLong = (long) powResult;
int longInt = (int) powLong;
System.out.println("Double = " + powResult + ", int = " + powInt + ", long = " + powLong + ", longInt = " + longInt);
}
}
結果:
C:\JavaTools>java PowTest
Double = 2.147483648E9, int = 2147483647, long = 2147483648, longInt = -2147483648
double - > int轉換是四舍五入的。 long - > int轉換被截斷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.