1. 程式人生 > 實用技巧 >4、Java基本資料型別

4、Java基本資料型別

一、基本資料型別

1、基本資料型別

JAVA中一共有八種基本資料型別,他們分別是 byte、short、int、long、float、double、char、boolean

型別型別位元組取值範圍
byte 整型 1byte -27 ~ 27-1
short 整型 2byte -215 ~ 215-1
int 整型 4byte -231 ~ 231-1
long 整型 8byte -263 ~ 263-1
float 浮點型 4byte 3.402823e+38 ~ 1.401298e-45
double 浮點型 8byte 1.797693e+308~ 4.9000000e-324
char 文字型 2byte 0~216-1
boolean 布林型 1byte true/false

在通常情況下,如果JAVA中出現了一個整數數字比如35,那麼這個數字就是int型的。如果我們希望它是byte型的,可以在資料後加上大寫的 B:35B,表示它是byte型的。同樣的35S表示short型,35L表示long型的,表示int我們可以什麼都不用加,但是如果要表示long型的,就一定要在資料後面加“L”。

double型比float型儲存範圍更大,精度更高,所以通常的浮點型的資料在不宣告的情況下都是double型的,如果要表示一個數據是float型的,可以在資料後面加上“F”。 浮點型的資料是不能完全精確的,所以有的時候在計算的時候可能會在小數點最後幾位出現浮動,這是正常的。

2、自動型別轉換

1)兩種型別是彼此相容的

2)轉換後的目標型別佔的空間範圍一定要大於被轉化的源型別

由低位元組向高位元組自動轉換(黑線表示無資料丟失的自動資料轉換,紅線表示轉換中可能發生精度丟失)

<關於int轉float發生精度丟失,而int轉double可以無資料丟失,可自行研究。

3、強制資料轉換

將容納更多資訊的資料型別轉換成一個容量更小的資料型別,可能存在精度損失的風險,編譯器要求程式設計師進行強制型別轉換。

強制轉換過程中可能發生資料溢位,必須警惕。

int a=(int)3.14;

4、資料型別自動提升

  如果兩個運算元其中有一個是double型別,另一個操作就會轉換為double型別。

  否則,如果其中一個運算元是float型別,另一個將會轉換為float型別。

  否則,如果其中一個運算元是long型別,另一個會轉換為long型別。

  否則,兩個運算元都轉換為int型別。

5、大資料型別

如果基本的整數和浮點數精度不夠滿足需求,那麼可以使用java.math包中的兩個很有用的類:BigInteger和BigDecimal。這兩個類可以處理包含任意長度數字序列的數值,BigInteger類實現了任意精度的整數運算,BigDecimal實現了任意精度的浮點數運算。 使用靜態的valueOf方法可以將普通的數值轉換為大數值:

BigInteger a = BigInteger.valueOf(100);

二、基本型別對應的包裝類

1、概述

雖然 Java 語言是典型的面向物件程式語言,但其中的八種基本資料型別並不支援面向物件程式設計,基本型別的資料不具備“物件”的特性——不攜帶屬性、沒有方法可呼叫。 沿用它們只是為了迎合人類根深蒂固的習慣,並的確能簡單、有效地進行常規資料處理。 這種藉助於非面向物件技術的做法有時也會帶來不便,比如引用型別資料均繼承了 Object 類的特性,要轉換為 String 型別(經常有這種需要)時只要簡單呼叫 Object 類中定義的toString()即可,而基本資料型別轉換為 String 型別則要麻煩得多。為解決此類問題 ,Java為每種基本資料型別分別設計了對應的類,稱之為包裝類(Wrapper Classes),也有教材稱為外覆類或資料型別類。

基本資料型別對應的包裝類如下圖:

2、裝箱和拆箱

2.1、什麼是裝箱和拆箱?

前面已經提到了,JAVA為每一個基本資料型別都提供了一個包裝器類,在JAVA SE5之前,如果要生成一個數值為10的Integer物件,需要這麼做:

Integer integer = new Integer(10); 而在JAVA SE5開始就提供了自動裝箱功能,如果要生成數值為10的Integer物件,只需要像下面這樣做就行了:

Integer integer = 10; 這樣寫會觸發自動裝箱,能直接根據數值就能建立對應的Integer物件,而不用new操作。

那麼拆箱是怎麼樣的呢?只需要像下面這樣做就行了:

Integer integer = 5;//裝箱 int i = integer;//拆箱 簡而言之,裝箱就是基本資料型別轉換為包裝器型別,拆箱就是包裝器型別轉換基本型別。

2.2、裝箱和拆箱的過程是什麼?

通過上面的介紹,知道了什麼是裝箱何拆箱。不過裝箱和拆箱的具體過程是什麼呢?其實裝箱和拆箱是呼叫了兩個函式來實現的,下面通過一段程式碼來說明:

 public class Main {
public static void main(String[] args) {
Integer integer = 5;
int i = integer;
}
}

反編譯這段程式碼生成的class檔案:

從反編譯的結果來看,裝箱的時候呼叫了Integer.valueOf(int i)這個函式,拆箱的時候呼叫了Integer.intValue()這個函式。

總的來說,裝箱的時候是呼叫的包裝器的valueOf這個函式,拆箱的時候呼叫的是包裝器的xxxValue這個函式(xxx是包裝器對應的基本資料型別)。

2.3、裝箱和拆箱關鍵原始碼分析

通過上面的介紹,我們知道了裝箱和拆箱關鍵在於valueOf和xxxValue這兩個函式,xxxValue這個函式沒有什麼值得注意的,就是把包裝器中的值裝換為對應的基本資料型別。而valueOf這個函式在不同的包裝器中,實現方法有很大的區別。

  下面,先介紹在Integer包裝器類中,該方法是怎麼實現的,原始碼如下:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

 private static class IntegerCache {
static final int high;
static final Integer cache[];

static {
final int low = -128;

// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}

private IntegerCache() {}
}

從上面的原始碼可以知道,通過valueOf建立Integer物件的時候,如果數值在區間[-128,127],那麼便返回指向IntegerCache.cache陣列中已經存在的物件的引用;否則建立一個新的Integer物件。簡而言之,建立Integer包裝器時,有一個數值在[-128,127]的緩衝池。當建立的物件數值在[-128,127]之間時,那麼不需要再在記憶體中開闢一個空間儲存,只需要將當前物件的引用指向該緩衝池中對應的物件,這樣效率上得到了提高,資源也沒有浪費。當然,這是Integer包裝器類的value函式,其他的包裝器不是這樣,有興趣的可以自己檢視原始碼,這裡不一 一詳解。