今天我们看一下,享元模式在Java Integer String中的应用,
享元模式在Java中的int包装类 Integer中,也有所体现,比如如下的代码
Integer i1 = 56;
Integer i2 = 56; Integer i3 = 129; Integer i4 = 129; System.out.println(i1 == i2); System.out.println(i3 == i4); |
返回一个true,一个false
为什么呢?
是因为其底层有了Integer的享元模式对象池,IntegerCache类,如果创建的对象在-128到127之间,会直接从IntegerCache中返回,如果不在Cache中,才会调用new的方法去创建
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } |
这就是享元模式下的Integer对象池
具体的JDK源码如下
/**
* Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE – (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high – low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } |
在IntegerCache的代码实现中,可以看出,会在加载类的时候,直接创建从-128到127的对象池,然后在后续的使用中,直接取出即可
而且提供了设置最大缓存值的方式,可以去调整最大缓存值
//方法一:
-Djava.lang.Integer.IntegerCache.high=255
//方法二:
-XX:AutoBoxCacheMax=255
除此外,Long Short Byte,都利用了享元模式来缓存数据,比如Long类型的LongCache享元工厂类
在String中,也有着享元模式
比如,如下的代码
String s1 = “小争哥”;
String s2 = “小争哥”;
String s3 = new String(“小争哥”);
System.out.println(s1 == s2);
System.out.println(s1 == s3);
上面是一个true,一个false
String也会开辟一段的存储区来存储字符串常量,这个存储区就是字符串常量池,
实际上,享元模式对于JVM的垃圾回收并不好,应为享元的工厂类中保存了享元对象的引用,导致了享元对象在没有任何使用的时候,也不容易被回收,所以使用享元模式,需要去验证,使用享元模式是否可以真正的节省内存,不然就不要过度的使用这个模式