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 }
在做如下判断时:
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; }
即便是equals,也是比较的intValue(),所以为了代码看起来更易读,还是直接使用VirusCheckRes.SAFE.getStatus().intValue() == virusRes.intValue(),比较好。
既然聊到了Integer,就在多扯两句,Integer与享元模式:
采用http://blog.csdn.net/gaoxueyi551/article/details/9091349中的例子:
View Code
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 } }
a1==a2 -> false可以理解,跟我的错误一样
i1==i2 -> true 就有点意思了
接下来
i3 = i4 -> false(与i1=i2有什么区别?)
i5 == i6 -> true 什么鬼
i7==i8 -> false
根据a1 != a2 ,i1 == i2, i5 == i6,可以看出,自动装箱用的应该是valueOf方法,而非构造方法,从反编译得到的字节码中也可以证明这点
源码为:
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() {} }
(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