天天看點

Java探秘之基本資料類型和包裝類(int,Integer)(一)

最近閑來無聊打算做一個部落格網,沒事記記筆記什麼,可是網站不好做,需要點時間,就先寫寫筆記來練練手。 可是要寫什麼呢,太難的好像我也寫不出來,萬一寫錯了誤導别人就不好了。 哈哈,不多說,直奔主題,要是寫的不好,大家可以提出來。 java有八種基本資料類型分别是,**char、shoat、int、float、double、long、byte、boolean。**     而它們對應的包裝類也有**,Character、Shoat、Integer、Float、Double、Long、Byte、Boolean。** 那麼他們之間有什麼差別呢,簡單來說他們是完全不同的概念,前者的java提供的基本資料類型,注意這裡說了是**基本資料類型**;而後者則是java為它們提供常見處理的**工具類**,注意說了是類也就是它們存在着對象。

 1. 初始化 這裡以int和Integer為例舉例說明,當我們初始化一個int和一個Integer并沒有給定他們值時,前者預設值為0,而後者預設為null(空對象)。

Java探秘之基本資料類型和包裝類(int,Integer)(一)
Java探秘之基本資料類型和包裝類(int,Integer)(一)

當我們需要傳入一個參數時,對int、Integer的選擇就很重要,如果我們傳入的Intger為null很有可能抛出一個空指針異常使我們的程式蹦掉;而選擇int時因為有初始值,不會出現Intger出現的問題,但是另一個問題也接踵而來, 我們不知道傳入的int值的多少,很有可能就會給我們的程式埋了一個影藏的bug;對于int還是Integer的選擇我們應該通過現實場景進行選擇。 這裡重點說一下,當我們使用MVC模式開發時,Controller接收參數如果參數不存在,而參數是int類型時就會抛出一個參數不存在異常,而Integer卻不會,隻是得到的參數為null。

Java探秘之基本資料類型和包裝類(int,Integer)(一)
Java探秘之基本資料類型和包裝類(int,Integer)(一)
Java探秘之基本資料類型和包裝類(int,Integer)(一)

2)自動拆箱,自動裝箱機制 自動拆箱和自動裝箱機制是在JDK1.5引進的一個新機制,觀察下面的代碼,為什麼會有這樣的結果産生呢。

Integer a = 34;
int b = 34;
Integer c = b;
int d = a;
System.out.println( a == b);
System.out.println( d == c);
           

基本資料類型的和其包裝類的互相轉換,這是為什麼呢? 答案很簡單,因為我們在執行Integer a = 34; 代碼時jdk預設執行的是Integer a = Integer.valueOf(34); 而我們在執行int d = a;時編譯執行的卻是int d = a.intValue(); 你可能會有疑問,為什麼會是這樣? 這個時候我們就需要打開源碼進行檢視尋找答案。

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
           

文檔是這樣說的,傳回一個制定int數值的Integer對象執行個體,這樣好像還不足以說明什麼,那我們要如何證明我們是對的呢? 我們可以檢視他的編譯檔案,一切就真相大白了(javac指令)。

public static void main(String[] var0) {
    new User();
    Integer var2 = Integer.valueOf(34);
    byte var3 = 34;
    Integer var4 = Integer.valueOf(var3);
    int var5 = var2.intValue();
    System.out.println(var2.intValue() == var3);
    System.out.println(var5 == var4.intValue());
}
           

這好像就不需要我在多說什麼了。 細心的小夥伴會看到文檔裡面有這麼一句話 * This method will always cache values in the range -128 to 127,  * inclusive, and may cache other values outside of this range.該方法會緩存-128到127之間的值,這句話又是什麼意思呢。

Integer a = 120;
Integer b = 120;
Integer c = 300;
Integer d = 300;
System.out.println( a == b);
System.out.println( d == c);
           

這兩句代碼會輸出社麼呢,小夥伴們肯定說都是true啊,或者說都是false。會這樣說的小夥伴不能說你錯了,隻能說你對了一半;是這樣的啊,我們知道==運算符進行運算時,運算符兩邊如果都為基本資料類型的話那就直接對數值進行比較;但是如果兩邊或者一邊為非基本資料類型時,即對象執行個體,則比較的是他們的記憶體位址(如果為空對象的話則為null),這裡很明顯兩邊都是對象執行個體,是以比較的是記憶體位址。

Java探秘之基本資料類型和包裝類(int,Integer)(一)

額?為什麼是這樣呢,按我們之前講得理論不是應該都為false才對嘛,因為他們比較的是記憶體位址呀。哈哈,這就是我們之前講到的問題,Integer會緩存-128到127之間的數值,而這麼數值當然是緩存在一個對象執行個體裡面啦,當我們需要使用時又進行取出(準确點來說是拿到的是它的引用),而不在這個範圍内的數值當然都是重新建立執行個體啦,有興趣的小夥伴可以進去看下源碼。 3) 類型轉換 這是包裝類很大的存在原因,試想一下,我們有一個數值傳遞過來時是String或者說是Object類型,我們要怎麼轉換成int類型呢? Integer的ValueOf可以将一個String類型轉換成int。

Java探秘之基本資料類型和包裝類(int,Integer)(一)
Java探秘之基本資料類型和包裝類(int,Integer)(一)

使用強制類型轉換編譯器會報類型轉換異常(String類型無法轉換成Integert類型),使用valueof方法則可以通過編譯,運作結果也是正确的;那麼在試想一下,如果是 String a = "120.0";那會是怎麼樣的結果呢。

Java探秘之基本資料類型和包裝類(int,Integer)(一)

抛出一個異常,不能輸入字元串為“120.0”,a是浮點類型的,那怎麼辦,總會有解決方法的。

Java探秘之基本資料類型和包裝類(int,Integer)(一)

哎呦,好像行不通,Float精度比Integer高,嗯!強轉?

Java探秘之基本資料類型和包裝類(int,Integer)(一)

也不行,好像很絕望。 Integer b = Float.valueOf(a).intValue(); 好像行了,測試一下。

還真行,什麼情況,這個intValue又是個什麼方法。

/**
 * Returns the value of this {@code Float} as an {@code int} after
 * a narrowing primitive conversion.
 *
 * @return  the {@code float} value represented by this object
 *          converted to type {@code int}
 * @jls 5.1.3 Narrowing Primitive Conversions
 */
public int intValue() {
    return (int)value;
}
           

什麼,居然是個強轉,搞了半天還是強轉,那為啥我們那樣轉不行呢,因為我們是類強轉,而它是類型轉換。

挖槽還真可以,說明這就沒錯了。 4)記憶體使用 這次那long類型來舉例,因為這樣舉例會比較明顯,我們知道long類型是占8個位元組(占用跟系統有關),而Long包裝類呢,卻是一個對象。

Long start = System.currentTimeMillis();
Long l = 0L;
for (Integer i = 0; i < Integer.MAX_VALUE; i++){
    l++;
}
System.out.println(System.currentTimeMillis() - start);
           

這段代碼會執行多久呢,好像是一瞬間的事,可是他執行了13060ms,可能這關系到機器,但是這個問題是很嚴重的,如果不小心寫了這樣的代碼,搞蹦一個程式是很簡單的事情。 這裡每次執行l++操作其實都相當于建立了一個新的執行個體,那這個量就非常大了,而如果換成基本資料類型的話,從始至終它都是8個位元組。 我們修改一下程式

Long start = System.currentTimeMillis();
long l = 0L;
for (int i = 0; i < Integer.MAX_VALUE; i++){
    l++;
}
System.out.println(System.currentTimeMillis() - start);
           

那麼它的運作時間又是多少呢?78ms 是不是很驚訝,相差了好幾百倍,是以我們絕對不可以出現這樣的代碼,對于基本資料類型還是包裝類的選擇,我們首選還是基本資料類型,而當某些場景無法繼續使用基本資料類型時,我們才使用包裝類進行處理。 OK,到此為止,基本資料類型跟包裝類之間的關系和差別我就講完了,如果有講的不好或者是講得不對的地方大家一定要指出來,不然我就沒法進步了。

到時候部落格開通了,還需要各位老少爺們捧場哈。

作者: 小醜魚yang 

連結:http://www.imooc.com/article/17521 來源:慕課網