1. 程式人生 > 其它 >java 查詢 基本型別 包裝類_Java探祕之基本資料型別和包裝類(int,Integer)

java 查詢 基本型別 包裝類_Java探祕之基本資料型別和包裝類(int,Integer)

技術標籤:java 查詢 基本型別 包裝類

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(空物件)。

49d13b44762c59ec6020ad6f1c2e445b.png

0ea27e30ea8294983807dcc96e44bc9a.png


當我們需要傳入一個引數時,對int、Integer的選擇就很重要,如果我們傳入的Intger為null很有可能丟擲一個空指標異常使我們的程式蹦掉;而選擇int時因為有初始值,不會出現Intger出現的問題,但是另一個問題也接踵而來,

da6d11288d2829fc4c981c1a85c87d5b.png

17bf0812a058c8e9f9f67d4554ff8d31.png

064d39c3de460b97ab5bbea2e5c6ce98.png

我們不知道傳入的int值的多少,很有可能就會給我們的程式埋了一個隱藏的bug;對於int還是Integer的選擇我們應該通過現實場景進行選擇。
這裡重點說一下,當我們使用MVC模式開發時,Controller接收引數如果引數不存在,而引數是int型別時就會丟擲一個引數不存在異常,而Integer卻不會,只是得到的引數為null。

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),這裡很明顯兩邊都是物件例項,所以比較的是記憶體地址。

82b2ca7b88fd657f5fd8477e7497893b.png

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

558b0cc0d5d4af5916ea135109837b65.png

2f4b52388a87d49e4fefd96a78ad2bce.png

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

71d3581ddaada102fc3ced1d3928b9ce.png

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

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

31559f23b2271a992a87c71cd5480a95.png

也不行,好像很絕望。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,到此為止,基本資料型別跟包裝類之間的關係和區別我就講完了,如果有講的不好或者是講得不對的地方大家一定要指出來,不然我就沒法進步了!
    都看到這裡了點個贊再走唄。