Java Grammer:資料型別
Java的資料型別
我們知道,Java是一種強型別語言,型別對於Java語言來說非常的重要不言而喻,在Java中,分為基礎資料型別和引用資料型別,其中基礎資料型別分為了四類八種:
下面,我們來分別說一下這四類八種
整形
首先,需要說明一點,在Java的整形中不存在unsigned
型別的數值,也就是說Java的整形都是有符號的可為正,可為負的整數
名稱 | 取值範圍 | 位元組數 | 位數 | 包裝類 |
---|---|---|---|---|
byte | \(-2^7\) 到 \(2^7-1\) | 1 | 8 | Byte |
short | \(-2^{15}\) 到 \(2^{15}-1\) | 2 | 16 | Short |
int | \(-2^{31}\) 到 \(2^{31}-1\) | 4 | 32 | Integer |
long | \(-2^{63}\) 到 \(2^{63}-1\) | 8 | 64 | Long |
可以看出,取值範圍取決於該型別的位數,由於Java的程式碼是執行在JVM中,所以該型別是獨立於機器之外存在的,與機器的關係並沒有很大,大大的提高了程式碼的可移植性。
在書寫程式碼的時候,我們需要注意,在我們定義一個long
型別的變數時,一定要記得在程式碼後加上大寫的L(小寫的l在某些字型下容易被認證1,給程式碼的可讀性帶來影響)。
整形預設型別
我們的整數預設型別是int型別,在我們進行計算的時候,會預設按照int型別進行計算。
byte a = 127; //right byte b = 1; //right byte c = a + b; // wrong byte d = 127 + 1; //wrong
編譯器報錯兩處,均是下面的這個錯誤資訊:
HelloWorld.java:7: 錯誤: 不相容的型別: 從int轉換到byte可能會有損失
byte c = a + b; // wrong
^
HelloWorld.java:9: 錯誤: 不相容的型別: 從int轉換到byte可能會有損失
byte d = 127 + 1; //wrong
這是一道很常見的面試題,其中錯誤的原因有兩點:
- 編譯器可以識別常量,但是無法識別變數,常量可以在編譯期間判斷是否超出範圍,但是兩個變數相加,編譯器在編譯期間無法得知,所以會報錯。
- 編譯器在編譯期將該值作為int型別進行預編譯計算後發現超出byte的取值範圍,但是又是通過一個byte型別的變數去接收,所以就會出現可能會損失精度的異常。
這裡很好的體現了整數型別的預設計算型別就是int型別~
浮點型別
浮點型有兩種,一種是32位的float
型別(單精度),一種是64位的double
型別(雙精度)。
名稱 | 取值範圍 | 位元組數 | 位數 | 包裝類 |
---|---|---|---|---|
float | 大約\(-3.4E+38\) 到 \(+3.4E38\) | 8 | 32 | Float |
double | 大約\(-1.7E-308\) 到 \(1.7E308\) | 16 | 64 | Double |
因為double
的取值範圍更廣,精度更高,所以我們日常都是使用double
,預設的浮點型別也是double
。
關於float和long
從上面我們可以知道float是32位的,而long是64位的,下意識的我們會認為64位的取值範圍必定要大於32位的,但事實並非如此:
float佔了4個位元組,也就是32位,其中第一位是符號位,23位是尾數位,剩下的8位都是指數位,\(2^{8}\)為256,由於(signed)符號數的原因,也就是說,float的取值範圍大致位於\(2^{-126}\)到\({2^{127}}\),是要遠遠的大於long的取值範圍的。
其實,這也詮釋了另外一個浮點數問題,因為計算機是二進位制的,所以無法精確的表示出浮點數,但是Java也給我們了一種解決方案,那就是我們在涉及到浮點數比較敏感的地方(比如經緯度,金錢)的時候,一定要注意使用BigDecimal
傳參為字串的方式!
三個特殊的浮點數值:
- 正無窮大(Double.POSITIVE_INFINITY)
- 負無窮大(Double.NEGATIVE_INFINITY)
- NAN(Double.NaN)
字元型
char
關鍵字所修飾的型別是字元型,需要由單引號引起來,一個或兩個char
型別的數值可以表示一個Unicode
字元,我們所熟知的字串底層資料結構正是一個字元陣列常量:
/** The value is used for character storage. */
private final char value[];
char
型別其實是由\u+十六進位制資料的組成的
,最大值為\uffff(65535)
,最小值為\u0000(0)
。
這裡需要注意一些特殊的轉義字元:
轉義序列 | 名稱 | Unicode值 |
---|---|---|
\b | 退格 | \u0008 |
\t | 製表 | \u0009 |
\n | 換行 | \u000a |
\r | 回車 | \u000d |
\" | 雙引號 | \u0022 |
\' | 單引號 | \u0027 |
\\ | 反斜槓 | \u005c |
布林型
boolean
修飾的變數就是布林型,布林型別很簡單,只有true false
兩個值,但是這裡需要注意,和C++不同的地方是它不能由數字0或1轉換成布林型。
強制型別轉換
byte a = 127; //right
byte b = 1; //right
byte c = a + b; // wrong
byte d = (byte)(a + b) // right
System.out.println(d);
還是這個熟悉的例子,剛剛我們已經分析了第三種情況為什麼會報錯,這裡我們可以通過強制型別轉換來強制完成這個操作。
強制型別轉換隻發生在位數較多的型別(int,64位)轉為位數較少(byte,8位)的型別。
果不其然,我們將第三句註釋掉之後,程式碼可以正常編譯通過,然後我們去執行的時候,發現列印的d的值如下:
-128
這裡就說到了強制型別轉換會發生的一種情況,如果被轉換的數值超出目標型別的取值範圍,就會發生資料的丟失。
二進位制在計算的時候,發生了超出資料範圍的進位操作,隨著強制型別轉換,進位的部分被咔嚓掉,然後就發生這種情況了(熟悉原反補的同學應該明白這一點)。
var
JDK 10中推出了一種新的型別var
,猛地看起來很像javascript
中的var
,它可以這麼玩:
var list = new ArrayList<String>();
var x = 3;
乍一看,還真的和javascript
有些像,但其實並不然,並不會影響Java是一個強型別語言的事實,它是基於區域性變數推斷機制來完成的,編譯器在處理var時,先讀構造器,並將它作為變數的型別,然後將該型別寫入位元組碼當中。也就是說,該型別是無法更改的。
var a = 3;
a = [1,2,3];
這樣的寫法在javascript
中毫無問題,但是在Java中就不行。但是需要注意,var
只能作用於帶有構造器的區域性變數和for迴圈中。
本篇重點總結
- 資料型別四類八種
- float取值範圍要大於long
- 強制轉換隻發生在高位轉低位
- var型別的原理是區域性型別推斷
公眾號
原創文章,才疏學淺,如有不對之處,萬望告知!