1. 程式人生 > >重拾Java(1)-基本資料型別與字面值

重拾Java(1)-基本資料型別與字面值

Java是一種強型別化的語言,每個變數都有一種型別,每個表示式也都有一種型別,並且每一種型別都是嚴格定義的。所有的賦值操作不管是顯式的還是在方法中呼叫中通過引數傳遞的,都要經過型別相容性檢查。

一、基本資料型別

1.1、概述

Java定義了八種基本資料型別:byte,short,int,long,char,float,double,boolean
基本資料型別也稱為簡單型別,這些型別可以分為四組:

  1. 整型。包括byte,short,int,long。用於表示有符號整數。
  2. 浮點型。包括float,double。用於表示帶小數位的數字。
  3. 字元型。包括char。用於表示字符集中的符號。
  4. 布林型。包括boolean。用於表示true/false值。

開發者可以直接使用這些型別,也可以使用它們來構造陣列以及自定義型別。因此,它們形成了所有可以建立的其他型別的基礎。
Java在其他方面是完全面向物件的,但基本資料型別並不是面向物件的,這樣設計的原因是為了效率。將基本資料型別設計為物件會極大地降低效能。

因為Java語言的特色之一就是具備可移植性,即不管在哪個平臺下執行,一份程式碼無需修改就可以直接執行。為了確保這一點,基本資料型別被定義為具有明確的範圍和數學行為,與C和C++這類語言“允許整數的大小隨著執行環境的要求而變化”不同,Java語言的資料型別都具有嚴格定義的範圍。無論在那種平臺下,int總是32位的。
雖然嚴格指定基本資料型別的範圍在某些環境下會造成效能損失,但這是為了實現可移植性而必須付出的。

1.2、整型

Java定義了四種整數型別:byte,short,int,long。所有這些型別都是有符號的、正的整數或者負的整數。Java不支援無符號(正值)的整數。

名稱 寬度 範圍
long 64 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
int 32 -2 147 483 648 ~ 2 147 483 647
short 16 -32 768 ~ 32767
byte 8 -128 ~ 127

當中,最常用的整數型別是int。int型別經常用於控制迴圈變數和索引陣列。對於那些不需要更大範圍的int型別數值的情況,你可能會認為使用範圍更小的byte和short型別效率會更高,然而事實並非如此。因為在表示式中使用byte和short值時,當對錶達式求值時它們會被提升為int型別。所以,當需要使用整數時,int通常是最好的選擇。

1.3、浮點型

浮點數也稱為實數,當計算需要小數精度的表示式時使用。

名稱 寬度 範圍
float 32 1.4e-045 ~ 3.4e+038
double 64 4.9e-324 ~ 1.8e+308

1.3.1、float

float型別表示使用32位儲存的單精度數值。在某些處理器上,單精度執行速度更快,並且佔用的空間是雙精度的一半,但是當數值非常大或者非常小時會變得不精確。如果需要小數部分,且精確度要求不高時,就可以考慮使用float型別。

1.3.2、double

double型別表示使用64位儲存的雙精度數值。在sin()、cos()和sqrt()這類數學函式中,返回值都是double型別。如果需要在很多次迭代運算中保持精度,或是操作非常大的數值時,double型別是最佳選擇。

1.4、字元型

char是用於儲存字元的資料型別。Java的設計初衷是允許程式設計師編寫在世界範圍內均可使用的語言,因此採用了Unicode標準來表示字元。Unicode定義了一個完全國際化的字符集,能夠表示全部人類語言中的所有字元,為此需要使用十六位寬度來儲存。char的範圍是0 ~ 65536,沒有負的char值。
對於一些語種,例如英語、德語等,可以使用八位寬度來表示這類語言的字元,使用Unicode在一定程度上會降低效率,但這是為了在全球獲得可移植性而必須付出的代價。
儘管char被設計為容納Unicod字元,但也可以用作整數型別,可以對char型別的變數執行算術運算。

1.5、布林型

boolean用於表示邏輯值,只能是true或false兩個值之一。所有的關係運算都返回boolean型別值。

二、字面值

2.1、整型字面值

所有的整數值都是整型字面值,例如10、07、0x15、0B1010等。
除了最常用的十進位制外,Java還提供了其他的進位制型別。
在Java中,八進位制以0開頭,例如06、04等。
十六進位制以0x或0X開頭,十六進位制數字的範圍是0~15,因此使用A~F(或a~f)替代數字10~15,例如0x12f、0xa等。

從JDK 7開始,可以使用二進位制指定整型字面值。為此,使用0b或0B作為數值的字首。例如,下面用二進位制字面值指定十進位制值10:

int x = 0b1010;

此外,從JDK 7開始,在整型字面值中還可以嵌入一個或多個下劃線,用於分隔開很大的整數,幫助閱讀。例如:

int x = 123_456_789;

下劃線只能用於分隔數字,不能位於字面值的開頭和結尾。此外,連續使用多個下劃線是允許的。

需要注意的是,整型字面值用於建立int型別數值。既然Java是強型別化的,那如何將整型字面值賦值給其他整數型別,如byte或long,而不會導致型別匹配錯誤呢?
其實,當將整型字面值賦值給byte變數時,如果字面值位於目標型別的範圍之內,就不會產生錯誤。整型字面值總是可以賦給long變數,也可以將整數賦給char,只要在char型別的範圍之內即可。

2.2、浮點型字面值

浮點數表示具有小數部分的十進位制數值,可以使用標準計數法或科學計數法表示浮點數。
標準計數法由前面的整數部分、其後的小數點以及小數點後面的小數部分構成。例如,10.001、1.456等。
科學技術法使用一個由標準計數法表示的浮點數加上一個字尾表示,其中的字尾指定為10的冪,與前面的浮點數是相乘的關係。指數部分用E(或e)後面跟上一個十進位制數表示,該十進位制數正負都可以。例如,7.22E20、24.3e-6等。

在Java中,浮點數字面值預設是雙精度的。為了指定浮點型字面值,需要為常量新增一個F或f為字尾,也可以通過附加D或d為字尾來顯式地指定double字面值。
從JDK 7開始,在浮點型字面值中同樣可以嵌入一個或多個下劃線。

2.3、布林型字面值

布林型字面值只有兩個邏輯值——true和false。true和false不能轉換成任何數字表示形式。

2.4、字元型字面值

Java中的字元被索引到Unicode字符集,它們是可以可以轉換成整數的十六位值,並且可以使用整數運算子進行操作。字元型字面值使用位於一對單引號中的字元來表示。對於那些不能直接輸入的字元,可以通過轉義字元序列輸入需要的字元。

轉義序列 含義
\’ 單引號
\” 雙引號
\\ 反斜槓
\r 回車鍵
\n 換行符
\f 換頁符
\t 製表符
\b 回格符

2.5、字串字面值

指定字串字面值的方法與其他大多數語言一樣,使用位於一對雙引號中的字元序列來表示。例如:”Hello world”。

三、型別轉換

在Java中,當將某種型別的值賦給另外一種型別的變數時,如果兩種型別是相容的,那麼Java會自動進行型別轉換,例如,int型別總是可以賦給long型別的變數。然而,並不是所有型別都是相容的,因此並不是所有型別轉換預設都是允許的。例如,不能從double型別預設轉到byte型別,在這種情況下,需要進行強制轉換(cast)。

3.1、自動型別轉換

當將某種型別的資料賦給另一種型別的變數時,如果滿足如下條件,則可以發生自動型別轉換:

  • 兩種型別是相容的
  • 目標型別大於源型別

當滿足這兩個條件時,會發生擴寬轉換。例如,要儲存所有有效的byte值,int型別是足夠的,所以不需要進行顯式的強制轉換語句。
對於擴寬轉換,數值型別(包括整型和浮點型)是相互相容的。然而,不存在從數值型別到char和boolean型別的自動轉換,char和boolean相互之間也是不相容的。
當將字面整數常量儲存到byte、short、long或char型別的變數中時,Java會執行自動型別轉換。

        int i=1;

        double j=1.2;

        //錯誤,不存在從整型到char型別的自動轉換
        char c1=i;
        //錯誤,不存在從浮點型到char型別的自動轉換
        char c2=j;
        //正確,字面整數常量儲存到char型別會自動型別轉換
        char c3=10;

3.2、強制型別轉換

因為byte型別的範圍比int型別小,所以如果將int型別的值賦給byte變數,不會自動執行型別轉換。
為了實現兩種不相容型別之間的轉換,需要使用強制型別轉換。這種轉換有時被稱為縮小轉換,因為是顯式地使數值變得更小以適應目標型別。

        int a=10;
        byte b;
        //編譯器報錯
        b=a;
        //強制型別轉換,編譯器不報錯
        b=(byte) a;

當將int型別的值強制轉換為byte型別時,如果int型別的值超出了byte型別的範圍,轉換結果將會發生很大變化。
當將浮點值賦給整數型別時會發生另一種型別的轉換:截尾。因為整數沒有小數部分,將浮點數賦給整數型別時,小數部分會丟失。
例如,參考以下一段程式的輸出結果:

    public static void main(String[] args) {
        int i=10000000;
        double d=111.11;
        byte b=(byte) i;
        float f=(float) d;
        System.out.println("b的值:"+b);
        System.out.println("f的值:"+f);
        b=(byte) d;
        System.out.println("b的值:"+b);
    }
b的值:-128
f的值:111.11
b的值:111

四、表示式中的自動型別提升

除了賦值外,在表示式中也可能會發生型別轉換。在表示式中,中間值要求的精度有時會超出運算元的範圍。
例如:

byte a = 40;
byte b = 50;
byte c = 100;
int d = a * b / c;

中間部分a*b很容易超出byte運算元的範圍。為了解決這類問題,當對錶達式求值時,Java會自動將每個byte,short或char運算元提升為int型別。這意味著使用int型別而不是byte型別執行子表示式 a * b。因此,即時a和b都被指定為byte型別,中間表示式(50 * 40)的結果2000是合法的。

自動型別提升很有用,但有時候會導致難以理解的編譯時錯誤。例如:

        byte b=10;
        //錯誤
        b= b*2;

如上程式碼試圖將 10 * 2 的結果(一個完全有效的byte值)儲存到byte變數中,但是編譯器卻提示錯誤。
當計算表示式的值時,運算元被自動提升為int型別,所以結果也被提升為int型別。因此,現在是試圖將一個int型別值轉為byte變數,如果不使用強制型別轉換,就不能將結果賦給byte變數。

Java定義了幾個應用於表示式的型別提升規則。

  1. 對於一元操作符來說,如果運算元的型別是byte,short或char,運算結果提升為int型別
  2. 對與二元操作符來說,提升規則是從以下幾條依次選擇一條執行
    • 如果運算元型別均為byte、short或char,那麼兩個數均轉為int型別,結果數也將為int型別
    • 如果運算元包含double型別,那麼另一個運算元也轉為double,結果數也將為double型別
    • 如果運算元包含float型別,那麼另一個運算元也轉為float,結果數也將為float型別
    • 如果運算元包含long型別,那麼另一個運算元也轉為long,結果數也將為long型別