[英]Java: why do I receive the error message "Type mismatch: cannot convert int to byte"
如果您聲明 byte 或 short 類型的變量並嘗試對它們執行算術運算,則會收到錯誤“類型不匹配:無法將 int 轉換為 short”(或相應地“類型不匹配:無法將 int 轉換為字節”)。
byte a = 23;
byte b = 34;
byte c = a + b;
在這個例子中,編譯錯誤在第三行。
盡管算術運算符被定義為可以對任何數字類型進行運算,但是根據Java語言規范(5.6.2二進制數字提升),字節和short類型的操作數在被傳遞給運算符之前會自動提升為int。
要對byte或short類型的變量執行算術運算,必須將表達式用括號括起來(在括號內將以int類型進行運算),然后將結果轉換回所需的類型。
byte a = 23; byte b = 34; byte c = (byte) (a + b);
這是真正的Java專家的一個后續問題:為什么? byte和short類型是完美的數字類型。 為什么Java不允許對這些類型進行直接算術運算? (答案不是“精度下降”,因為沒有明顯的理由首先將其轉換為int。)
更新:jrudolph建議此行為基於JVM中可用的操作,尤其是僅實現全字和雙字運算符。 因此,對於字節和短褲運算符,必須將它們轉換為int。
您的后續問題的答案在這里:
byte和short類型的操作數在交給操作員之前會自動提升為int
因此,在您的示例中,將a
和b
都轉換為int
然后再交給+運算符。 將兩個int
相加的結果也是int
。 然后嘗試將int
分配給byte
值會導致錯誤,因為可能會丟失精度。 通過顯式轉換結果,您將告訴編譯器“我知道我在做什么”。
我認為問題是,JVM僅支持兩種類型的堆棧值:字大小和雙字大小。
然后,他們可能決定只需要一個對堆棧上字長的整數進行運算的操作。 因此,在字節碼級別只有iadd,imul等(並且沒有用於字節和短褲的運算符)。
因此,您將得到一個int值,這些操作是Java無法安全地轉換回較小字節和short數據類型的結果。 因此,它們迫使您強制將值縮小到字節/短。
但是最后您是對的:例如,此行為與int的行為不一致。 您可以毫無疑問地添加兩個整數,並且如果結果溢出也不會出錯。
Java語言始終將算術運算符的參數提升為int,long,float或double。 因此,采用以下表達式:
a + b
其中a和b是字節類型。 這是以下內容的簡寫:
(int)a + (int)b
此表達式的類型為int。 將int值分配給字節變量時,給出錯誤顯然很有意義。
為什么要用這種方式定義語言? 假設a為60而b為70,則a + b為-126-整數溢出。 作為可能導致int的更復雜表達式的一部分,這可能會成為一個困難的錯誤。 限制使用字節和數組存儲的簡短形式,文件格式/網絡協議和拼圖的常量。
JavaPolis 2007上有一個有趣的記錄。JamesGosling給出了一個例子,說明無符號算術有多么復雜(以及為什么Java中沒有它)。 喬什·布洛赫(Josh Bloch)指出,他的例子在正常的有符號算術下也給出了錯誤的例子。 對於可理解的算法,我們需要任意精度。
在 Java 語言規范(5.6.2 二進制數字提升)中:
1 如果任何表達式為 double 類型,則提升的類型為 double,其他非 double 類型的表達式經歷擴展原始轉換為 double。
2 否則,如果任何表達式是 float 類型,則提升的類型是 float,並且其他非 float 類型的表達式經歷擴展原始轉換為 float。
3 否則,如果任何表達式為 long 類型,則提升的類型為 long,並且其他非 long 類型的表達式經歷擴展原始轉換為 long。
4 否則,所有表達式都不是 double、float 或 long 類型。 在這種情況下,提升的類型是 int,並且任何不是 int 類型的表達式都會經歷擴展原始轉換為 int。
您的代碼屬於案例 4。變量a
和b
在交給+
運算符之前都轉換為int
。 +
操作的結果也是int
類型而不是byte
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.