享元模式(Flyweight)/ 轻量级模式
共享细粒度对象,不必为每个访问者单独创建一个对象,以此降低内存消耗。
内部状态、外部状态
享元模式将对象的状态分为内部状态、外部状态。内部状态即不变,外部状态即变化。通过共享不变的部分,达到减少对象数量并节约内存。
内部状态:比如连接池中的配置,这些配置信息是不会变化的。
外部状态:比如连接池中的连接,各个连接有不同的状态,有些受状态影响可被回收。
一般配合工厂模式使用,如果缓存中有,则直接返回,如果没有则新建一个对象并放在缓存中,最后返回。
应用场景
- 将一组数据封装在对象中,然后缓存该对象,并提供给多出使用。
- 常用于系统底层开发,以解决性能问题。
- 系统有大量相似对象、需要缓冲池的场景。
比如:
1) 房产中介房源信息共享。
2) 全国社保联网,数据共享。
3) String – 常量
4) Integer Integer.valuesOf // -128~127 放在cache中
代码实现
map 中存储,外部获取对象时,map中有则直接返回
public class Factory {
private static final HashMap<String, Persion> map = new HashMap<>();
public Persion get(String id){
Object obj = map.get(id); // 先从map中获取,没有再new
if(obj == null){
return new Persion("qq", 1);
}
return (Persion) obj;
}
}
String
public class StringTest {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = "he" + "llo";
String s4 = "he";
String s5 = "llo";
String s6 = s4 + s5;
String s7 = new String("hello");
System.out.println("s1 == s2 :"+(s1 == s2)); // 同一个常量
System.out.println("s1 == s3 :"+(s1 == s3)); // 编译时"he" + "llo"优化成"hello"
System.out.println("s1 == s6 :"+(s1 == s6)); // 编译时s4 s5是引用(类似分派调用)
System.out.println("s1 == s7 :"+(s1 == s7)); // new 新的地址引用
}
}
输出结果:
s1 == s2 :true
s1 == s3 :true
s1 == s6 :false
s1 == s7 :false
总结:
- "hello"为常量,“he” + “llo"编译时优化成"hello”,所以s1、s2、s3是相等的。
- new 之后,就会生成新的地址引用,就不相等了。
- s4 + s5是引用,跟"he" + "llo"不同。
Integer
public class IntegerTest {
public static void main(String[] args) {
int i1 = 128;
Integer i2 = new Integer(128);
Integer i22 = new Integer(128);
System.out.println("i1 == i2 : " + (i1 == i2)); // int 等于 Integer
System.out.println("i2 == i22 : " + (i2 == i22)); // new Integer 不等于 new Integer
Integer i3 = Integer.valueOf(127);
Integer i4 = Integer.valueOf(127);
System.out.println("i3 == i4 : " + (i3 == i4)); // valueOf源码中,-128 - 127 是从cache中获取的
Integer i5 = Integer.valueOf(128);
Integer i6 = Integer.valueOf(128);
System.out.println("i5 == i6 : " + (i5 == i6));
}
}
输出结果
i1 == i2 : true
i2 == i22 : false
i3 == i4 : true
i5 == i6 : false
总结:
- int 等于 Integer
- new Integer 不等于 new Integer
- valueOf源码中,-128 - 127 是从cache中获取的
源码中的应用
Integer.valueOf()
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Long.LongCache{}
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}