Integer類型與享元模式

工程中某方法返回一個Integer:virusRes
另有:某枚舉類:
 1 public enum VirusCheckRes {
 2     
 3     UNKNOW(0), SAFE(1), HIGH_RISK(2), MEDIUM_RISK(3), LOW_RISK(4);
 4     
 5     private Integer status;
 6     private VirusCheckRes(Integer status){
 7         this.status = status;
 8     }
 9     public Integer getStatus() {
10         return this.status;
11     }
12     public void setStatus(Integer status) {
13         this.status = status;
14     }
15         
16 }
View Code

在作以下判斷時:html

if (VirusCheckRes.SAFE.getStatus() == virusRes) 

當virusRes和SAFE都=1 時,結果返回的false
 
老生常談的問題,即使是Integer這樣的基礎變量包裝類,判斷等於(==)的時候,也是比較對象的地址,而非對象的值,若是比較對象的值,請出門左拐用equals。
but!(Integer類源碼)
    public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
    }
View Code

即使是equals,也是比較的intValue(),因此爲了代碼看起來更易讀,仍是直接使用VirusCheckRes.SAFE.getStatus() .intValue() == virusRes .intValue(),比較好。
 
既然聊到了Integer,就在多扯兩句,Integer與享元模式:
採用 http://blog.csdn.net/gaoxueyi551/article/details/9091349中的例子:
public class Test {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  
  Integer a1 = new Integer(4);
  Integer a2 = new Integer(4);
  System.out.println(a1 == a2); //false
  
  
  Integer i1 = 13;
  Integer i2 = 13;
  System.out.println(i1 == i2); //true
  
  
  
  Integer i3 = 128;
  Integer i4 = 128;
  
  System.out.println(i3 == i4); //false
  
  Integer i5 = Integer.valueOf(3);
  Integer i6 = Integer.valueOf(3);
  System.out.println(i5 == i6); //true
  
  Integer i7 = Integer.valueOf(128);
  Integer i8 = Integer.valueOf(128);
  System.out.println(i7 == i8); //false
 

 }

}
View Code

a1==a2  -> false能夠理解,跟個人錯誤同樣java

i1==i2    -> true 就有點意思了設計模式

接下來數組

i3 = i4     -> false(與i1=i2有什麼區別?)ide

i5 == i6   -> true 什麼鬼ui

i7==i8     -> falsethis

 

根據a1 != a2 ,i1 == i2, i5 == i6,能夠看出,自動裝箱用的應該是valueOf方法,而非構造方法,從反編譯獲得的字節碼中也能夠證實這點spa

源碼爲:.net

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

反編譯的字節碼設計

一樣能夠看出,拆箱時,用的是intValue方法
 


那麼 爲何3還好好的,128通過裝箱以後就返回的false呢?
看了Integer的源碼真的感受jdk的強大啊,這裏用到了設計模式中的享元模式:
 
上文書說道裝箱用到了i1==i2和i5 == i6都返回了true,並且又說道這四個變量其實都用到了相同的方法valueOf,那麼就來看看valueOf
    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

IntegerCache.cache[] 是什麼鬼?
818
    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() {}
    }
View Code

(integerCacheHighPropValue貌似能夠經過JVM配置)
 
    // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
    private static String integerCacheHighPropValue;

從代碼中能夠看出,IntegerCache是Integer中的內部類,裏面定義了兩個屬性,high,cache,其中high在static塊中給出了賦值,若是配置integerCacheHighPropValue的話,默認的high是127,low=-128

如今再回過頭看
    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

若是i屬於[-128,127],則返回cache[i+128],cache如代碼所示,是IntegerCache的一個靜態數組,是 保存一份
所以,當自動裝箱的i在[-128,127]範圍內,則不生成新的Integer,而是共享了一個Integer對象。(享元模式)
超出該範圍的Integer才真正的new出了Integer對象。
 
其餘的如Long,Double,Float,Boolean等類型,再也不囉嗦。
以上。
 
 
 參考資料:
http://blog.csdn.net/gaoxueyi551/article/details/9091349
http://www.cnblogs.com/dolphin0520/p/3780005.html
http://1006836709.iteye.com/blog/1714378
相關文章
相關標籤/搜索