簡體   English   中英

Java長作業令人困惑

[英]Java long assignment confusing

為什么這個Java代碼

long a4 = 1L;
long a3 = 1;
long a2 = 100L * 1024 * 1024 * 1024;
long a1 = 100 * 1024 * 1024 * 1024;
System.out.println(a4);
System.out.println(a3);
System.out.println(a2);
System.out.println(a1);

運行時輸出

1
1
107374182400
0

而不是預期的

1
1
107374182400
107374182400

輸出?

 long a2 = 100L * 1024 * 1024 * 1024;

但是,在此操作中,至少一個操作數很long 因此該運算是使用64位精度執行的,並且數值運算符的結果為long類型。 另一個非long操作數通過數字提升擴展為long類型,結果值存儲到變量a2

 long a1 = 100 * 1024 * 1024 * 1024;

普通整數的常量表達式,表達式的結果計算為int類型。 但是,計算值太大而無法容納整數,因此會溢出,結果為0 ,並存儲到a1變量中。

編輯:如以下注釋中所述:

為什么不變成負數?

因為在進行整數計算時 ,第二次計算等效於25 * 2^32 ,其中^具有冪的含義,而2^32整數值為0 但是,要解釋為什么其值為0 :在二進制中:

 100 * 1024 * 1024 * 1024 == 25 * 2^32;

 Integer.MAX_VALUE =  2 ^ 31 -1 = 0 11111111 11111111 11111111 1111111
 Integer.MAX_VALUE + 1 = 2 ^ 31 = 1 00000000 00000000 00000000 0000000 

2 ^ 31是負整數( -2147483648 ),因為符號位為1 ,因此2 ^ 32只是22 ^ 31的乘積:向左移動,符號位將變為0 ,因此結果為0

查看java language specification: 4.2.2: Integer operation以獲取詳細信息。

107374182400恰好是整數(2 ^ 32)整個范圍的25倍 ,這意味着,如果嘗試將其擬合為整數,它將溢出 並且因為它恰好適合25次,所以最終精確地為0(這是一個巧合,其他巨大的乘法可能最終為正或負)。 而且您使用的是整數,直到達到長整型為止

long a1 = 100 * 1024 * 1024 * 1024;

相當於

int temp = 100 * 1024 * 1024 * 1024;
long a1 = (long)temp;

如果在表達式中放置單個long,則將強制使用long數學而不是整數數學,這可以消除問題

可能是a1右邊的表達式首先作為int計算,然后轉換為long 如果它的int等於0 ,則它將保持0 long

long a4 = 1L; //這沒問題

long a3 = 1; //此處左側的圖元被認為是整數,並且在賦值時將其強制轉換為long值,因此結果再次符合預期

long a2 = 100L * 1024 * 1024 * 1024; (在這里,您使用了100L,因此其他類型將被強制轉換為Long,因此預期輸出)

long a1 = 100 * 1024 * 1024 * 1024; (因為默認情況下,Java中任何原始數字都被視為int,它將將此視為整數乘法,因此超出范圍並導致0)

根據Lexical Literals文檔,其中提到:

文字的類型確定如下:
-以L或l結尾的整數文字(§3.10.1)的類型很長(§4.2.1)。
-任何其他整數文字的類型為int(第4.2.1節)。

因此,您的表達式100 * 1024 * 1024 * 1024被評估為int原始數據類型,因為在任何數字值中均未提及lL 結果為107374182400即在Binary中為1 1001 0000 0000 0000 0000 0000 0000 0000 0000int為32位,因此低32位如示例4.2.2-1中所述。 整數運算結果為0

在同一文檔中還提到:

如果除移位運算符外的整數運算符至少具有一個long類型的操作數,則使用64位精度執行該運算,並且數值運算符的結果為long類型。 如果另一個操作數不長,則首先將其加寬(第5.1.5節)以通過數字提升鍵入long

這意味着表達式中的任何值包含lL然后所有int值都將擴展為64位。

編輯評論中還要求

為什么不變成負數?

我認為它也回答了上述問題

原因是整數溢出
輸出為100 * 1024 * 1024 * 1024; 是一個不long的整數( int

long a2 = 100L * 1024 * 1024 * 1024; 您指定的值之一是long (此處為100L ),並且與該值相乘會導致long值正確存儲在a2

這是您的操作:您將100 * 1024 * 1024 * 1024分配給長數據類型,但是您沒有說100 * 1024 * 1024 * 1024是長值

默認情況下,java編譯器認為其為整數。 由於整數不能容納那么多值,因此將顯示錯誤的結果。 希望能幫助到你 !

在Java中,如果您具有int * int,它將把輸出計算為int。 如果您做int * long,則只會給出long的結果。 在您的情況下,100 * 1024 * 1024 * 1024的結果將溢出int。

因此,添加“ L”會使操作數變長,並且計算將值存儲在long中。 當然,不會發生溢出,並且可以輸出正確的結果(即a2)。

數字3起作用是因為您指定了100L的長型。 這就是為什么它是長乘法並且可以存儲的原因。 另一方面,數字4是最大2 ^ 32-1的整數乘法,這就是為什么您溢出並出現零默認值的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM