遇到一個題目:html
通過強制類型轉換之後,變量a,b的值分別爲多少?
short a = 128;
byte b = (byte) a;
a = ?, b = ?
答案是:a = 128, b = -128java
這涉及到 Java primitive type 的 conversion,打算藉此稍稍研究一下。oracle
下面分析中會涉及到一些與題目無關的細節,想直接看題目解答的請跳到 "題目中的數值在內存中的表示"ide
Java 的 conversion 有多種,這裏咱們只討論 primitive conversion。翻譯
primitive conversion 分爲兩種,一是 Widening Primitive Conversion(擴展型基本數據類型轉換),二是 Narrowing Primitive Conversion(窄化型基本數據類型轉換)。code
ps: 翻譯成中文仍是感受怪怪的,下面仍是用英文表示吧。orm
JLS 定義了 19 種 widening pc,簡單來講,就是位數低的向高的轉換,以下htm
widening pc 不會丟失數值的總體大小信息內存
這個問題涉及到的 int -> short 和 short -> byte 的轉換就包含在 JLS 定義的 22 種 narrowing pc 之中。get
須要注意的是 narrowing pc 是有可能丟失數值的總體信息以及損失精度和範圍的。
可能有人會注意到,上面的 widening pc 和 narrowing pc 都沒有包含 byte -> char 的轉換
Chapter 5. Conversions and Promotions
The following conversion combines both widening and narrowing primitive conversions:
byte to char
First, the byte is converted to an int via widening primitive conversion (§5.1.2), and then the resulting int is converted to a char by narrowing primitive conversion (§5.1.3).
這是由於這是一種特殊地、同時結合了 widening pc 和 narrowing pc 的轉換,byte 會先轉換成 int(widening pc),而後將這個 int 結果轉換成 char(narrowing pc)。
那麼咱們仍是回到這個問題
short a = 128;
byte b = (byte) a;
首先,在 Java 中,整數默認爲 int 類型,也就是說,在 short a = 128;
中,會發生 int -> short 的 narrowing pc,是有可能損失精度的,因爲 int 是高位(32位),short 是低位(16位),因此在轉換時會 truncate。一樣,對於 byte b = (byte) a;
也有可能由於 truncate 而損失精度。
在 Java 中數值是用補碼錶示的,在這裏回顧一下原碼、反碼、補碼的概念(以 3 爲例吧):
二進制表示:
int a = 128 00000000 00000000 10000000 00000000
short a = 128 00000000 10000000 (強轉後前面 16 位被截斷)
能夠看出來,a 的值輸出應該仍是 128
那麼對於 byte b = (byte) a;
二進制表示:
short a = 128 00000000 10000000
byte b = 128 10000000 (強轉後前面 8 位被截斷)
可是,輸出的 b 的值爲何不是 128 而是 -128 呢
Primitive Data Types (The Java™ Tutorials > Learning the Java Language > Language Basics)
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
這是由於 byte 是一個 8 位有符號二進制補碼整數,它包含的值的範圍是 [-128, 127],所以 byte 類型的值是沒法表示 128 的
那麼在發生截斷後,1000 0000 表示的就是一個補碼,從這個補碼能夠看出來它的原碼確定是一個負數,那麼咱們根據這個補碼反推獲得它的反碼:1111 1111,從而獲得它的原碼:1000 0000,能夠看出這個值就是 -0,可是在咱們的生活中是沒有 -0 的,因此在計算機中就把它識別成 -128,所以這就是爲何 b 的值的輸出是 -128 的緣由。
ps: 關於 -0 對應於 -128 的具體解釋,我懶得寫了,由於感受取決於我的的理解,不想細究,若是有人還有疑問,能夠看看這我的的解釋 byte類型取值範圍爲何是127到-128? - 知乎
那麼到這裏,問題就基本解釋清楚了,感受本身仍是很囉嗦,不過實際上是爲了回顧一些基礎的知識,也但願對其餘人有所幫助啦~