Java Grammar:數據類型


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傳參為字符串的方式!

三個特殊的浮點數值:

  1. 正無窮大(Double.POSITIVE_INFINITY)
  2. 負無窮大(Double.NEGATIVE_INFINITY)
  3. 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類型的原理是局部類型推斷

公眾號

原創文章,才疏學淺,如有不對之處,萬望告知!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM