簡體   English   中英

為什么 Java 的 +=、-=、*=、/= 復合賦值運算符不需要強制轉換?

[英]Why don't Java's +=, -=, *=, /= compound assignment operators require casting?

直到今天,我認為例如:

i += j;

只是一個捷徑:

i = i + j;

但是如果我們試試這個:

int i = 5;
long j = 8;

然后i = i + j; 不會編譯但i += j; 會編譯得很好。

這是否意味着實際上i += j; 是這樣的快捷方式i = (type of i) (i + j)嗎?

與這些問題一樣,JLS 擁有答案。 在這種情況下, §15.26.2 復合賦值運算符 摘錄:

E1 op= E2形式的復合賦值表達式等價於E1 = (T)((E1) op (E2)) ,其中TE1的類型,只是E1只計算一次。

引用自§15.26.2的示例

[...] 以下代碼是正確的:

 short x = 3; x += 4.6;

並導致 x 的值為 7,因為它等價於:

 short x = 3; x = (short)(x + 4.6);

換句話說,你的假設是正確的。

這種轉換的一個很好的例子是使用 *= 或 /=

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

或者

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

或者

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

或者

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

很好的問題。 Java 語言規范確認了您的建議。

例如,以下代碼是正確的:

 short x = 3; x += 4.6;

並導致 x 的值為 7,因為它等價於:

 short x = 3; x = (short)(x + 4.6);

是的,

基本上當我們寫

i += l; 

編譯器將其轉換為

i = (int)(i + l);

我剛剛檢查了.class文件代碼。

知道這真是一件好事

i = i + l情況下,您需要從long explicitlyint然后它將編譯並提供正確的輸出。 喜歡

i = i + (int)l;

或者

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

但在+=情況下,它工作正常,因為運算符隱式地將類型從右變量類型轉換為左變量類型,因此不需要顯式轉換。

這里的問題涉及類型轉換。

當你添加 int 和 long 時,

  1. int 對象被轉換為 long 並且兩者都被添加並且你得到了 long 對象。
  2. 但不能將 long 對象隱式轉換為 int。 所以,你必須明確地做到這一點。

但是+=的編碼方式是進行類型轉換。 i=(int)(i+m)

在 Java 中,當賦值操作右側的表達式類型可以安全地提升為賦值左側的變量類型時,會自動執行類型轉換。 因此我們可以安全地分配:

byte -> short -> int -> long -> float -> double.

反過來也一樣。 例如,我們不能自動將 long 轉換為 int,因為第一個需要比第二個更多的存儲,因此可能會丟失信息。 要強制進行這種轉換,我們必須執行顯式轉換。
類型 - 轉換

有時,這樣的問題可以在面試中提出。

例如,當你寫:

int a = 2;
long b = 3;
a = a + b;

沒有自動類型轉換。 在 C++ 中編譯上面的代碼不會有任何錯誤,但在 Java 中你會得到類似Incompatible type exception東西。

所以為了避免它,你必須像這樣編寫代碼:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

主要區別在於a = a + b沒有進行類型轉換,因此編譯器會因為您沒有進行類型轉換而生氣。 但是對於a += b ,它真正做的是將b類型轉換為與a兼容的類型。 所以如果你這樣做

int a=5;
long b=10;
a+=b;
System.out.println(a);

你真正在做的是:

int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);

這里的微妙之處...

j是 double 且i是 int 時, i+j有一個隱式類型轉換。 當它們之間存在操作時,Java總是將整數轉換為雙精度數。

為了澄清i+=j其中i是整數而j是雙精度可以描述為

i = <int>(<double>i + j)

參見: 隱式轉換的這個描述

在這種情況下,為了清楚起見,您可能希望將j類型轉換為(int)

Java 語言規范E1 op= E2定義為等效於E1 = (T) ((E1) op (E2)) ,其中TE1的類型,並且E1被評估一次

這是一個技術性的答案,但您可能想知道為什么會這樣。 好吧,讓我們考慮以下程序。

public class PlusEquals {
    public static void main(String[] args) {
        byte a = 1;
        byte b = 2;
        a = a + b;
        System.out.println(a);
    }
}

這個程序打印什么?

你猜到3了嗎? 太糟糕了,這個程序不會編譯。 為什么? 好吧,碰巧在 Java 中添加字節被定義為返回一個int 我相信這是因為 Java 虛擬機沒有定義字節操作來保存字節碼(畢竟數量有限),而是使用整數操作是一種語言中公開的實現細節。

但是,如果a = a + b不起作用,則意味着如果E1 += E2被定義為E1 = E1 + E2a += b永遠不會對字節起作用。 正如前面的例子所示,情況確實如此。 作為使+=運算符適用於字節和短褲的技巧,涉及到隱式轉換。 這不是什么了不起的黑客,但在 Java 1.0 工作期間,重點是讓語言發布開始。 現在,由於向后兼容,Java 1.0 中引入的這個 hack 無法刪除。

暫無
暫無

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

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