(轉)int和Integer的區別

轉:https://blog.csdn.net/zjfahs/article/details/90138277

1 區別

 

  • Integer是int的包裝類,int則是java的一種基本數據類型
  • Integer變量必須實例化後才能使用,而int變量不需要
  • Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數據值
  • Integer的默認值是null,int的默認值是0


2 ==比較


2.1、由於Integer變量實際上是對一個Integer對象的引用,所以兩個通過new生成的Integer變量永遠是不相等的(因爲new生成的是兩個對象,其內存地址不同)。
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

2.2、Integer變量和int變量比較時,只要兩個變量的值是向等的,則結果爲true(因爲包裝類Integer和基本數據類型int比較時,java會自動拆包裝爲int,然後進行比較,實際上就變爲兩個int變量的比較)
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
2.3、非new生成的Integer變量和new Integer()生成的變量比較時,結果爲false。(因爲非new生成的Integer變量指向的是java常量池中的對象,而new Integer()生成的變量指向中新建的對象,兩者在內存中的地址不同)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
2.4、對於兩個非new生成的Integer對象,進行比較時,如果兩個變量的值在區間-128到127之間,則比較結果爲true,如果兩個變量的值不在此區間,則比較結果爲false
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

對於第4條的原因:
java在編譯Integer i = 100 ;時,會翻譯成爲Integer i = Integer.valueOf(100);,而java API中對Integer類型的valueOf的定義如下:

public static Integer valueOf(int i){
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high){
        return IntegerCache.cache[i + (-IntegerCache.low)];
    }
    return new Integer(i);
}
java對於-128到127之間的數,會進行緩存,Integer i = 127時,會將127進行緩存,下次再寫Integer j = 127時,就會直接從緩存中取,就不會new了


    public static void main(String[] args) {

        int i1= 1;
        Integer i2 = 1;
        Integer i3 = new Integer(1);


        //true 因爲i2會被自己拆箱成1
        System.out.println( i1 == i2);

        //true 因爲i3會被自己拆箱成1
        System.out.println( i1 == i3);

        //false 因爲Integer會自動在類加載的時候,自動生成一個Integer數組,保存着 -128 ~ 127 的對象
        //i2 會被編譯成 i2= Integer.valueOf(1); valueOf方法會去獲取預先緩存的 -128 ~ 127 對象。
        // 所以這裏判斷的是 i2(這個在加載階段就創建的Integer對象) 和 i3(在執行階段才創建的對象) 是否同一個對象,當然不是同一個對象。
        System.out.println( i2 == i3);


        Integer i4 = 2;
        Integer i5 = 2;

        //true 因爲i4 和 i5 都是Integer類緩存的對象。
        System.out.println(i4 == i5);


        Integer i6 = 128;
        Integer i7 = 128;

        //false ,因爲i6 和 i7都大於127。所以是new出來的對象,而不是緩存的對象。
        System.out.println(i6 == i7 );


        Integer i8 = new Integer(3);
        Integer i9 = new Integer(3);
        //false i8 和 i9都是new出來的對象,是不同的引用。所以是false
        System.out.println(i6 == i7 );

        //true  equals方法是獲取int值進行對比。 他們的值都是3 所以是true
        System.out.println(i8.equals(i9));


    }

 

3 延伸


3.1、理解自動裝箱、拆箱


自動裝箱與拆箱實際上算是一種“語法糖”。所謂語法糖,可簡單理解爲Java平臺爲我們自動進行了一些轉換,保證不同的寫法在運行時等價。因此它們是發生在編譯階段的,也就是說生成的字節碼是一致的。

對於整數,javac替我們自動把裝箱轉換爲Integer.valueOf(),把拆箱替換爲Integer.intValue()。可以通過將代碼編譯後,再反編譯加以證實。

原則上,建議避免無意中的裝箱、拆箱行爲,尤其是在性能敏感的場合,創建10萬個Java對象和10萬個整數的開銷可不是一個數量級的。當然請注意,只有確定你現在所處的場合是性能敏感的,才需要考慮上述問題。畢竟大多數的代碼還是以開發效率爲優先的。

順帶說一下,在32位環境下,Integer對象佔用內存16字節;在64位環境下則更大。

 

3.2、值緩存


就像上一講談到的String,Java也爲Integer提供了值緩存。

Integer i1 = 1;Integer i2 = Integer.valueOf(2);Integer i3 = new Integer(3);

上述代碼中第一行與第二行的寫法取值使用了值緩存,而第三行的寫法則沒有利用值緩存。結合剛剛講到的自動裝箱、拆箱的知識,第一行代碼用到的自動裝箱,等價於調用了Integer.valueOf()。

不僅僅是Integer,Java也爲其它包裝類提供了值緩存機制,包括Boolean、Byte、Short和Character等。但與String不同的是,默認都只會將絕對值較小的值放入緩存。以Integer爲例,默認情況下只會緩存-128到127之間的值。當然如果你願意也可以通過以下JVM參數進行設置:

-XX:AutoBoxCacheMax=N

 

3.3、原始類型操作線程安全嗎?


這個問題的正確答案是“線程不安全”,是否有些出乎你的意料?

原始數據類型的變量,需要使用併發相關手段才能保證線程安全。特別的是,部分比較寬的數據類型,比如long、float、double,甚至不能保證更新操作的原子性,可能出現程序讀取到只更新了一半數據位的數值!關於這個話題會在這個專欄後面的併發主題詳細介紹。如果有線程安全的計算需要,建議考慮使用類似AtomicInteger、AtomicLong這樣線程安全的類。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章