目录
运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销,从而提高系统资源的利用率。
享元模式中存在以下两种状态:
享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。
享元模式的主要有以下角色:
俄罗斯方块中的方块不需要多次创建,使用享元模式可以省下极大内存空间
创建抽象享元角色
- public abstract class AbstractBox {
- //相当于内部状态为形状
- public abstract String getShape();
- //外部状态为颜色
- public void getColor(String color){
- System.out.println("形状为:"+getShape()+",颜色为:"+color);
- }
- }
创建具体享元角色
- public class IBox extends AbstractBox{
- @Override
- public String getShape() {
- return "I";
- }
- }
-
- public class LBox extends AbstractBox{
- @Override
- public String getShape() {
- return "L";
- }
- }
-
- public class OBox extends AbstractBox{
- @Override
- public String getShape() {
- return "O";
- }
- }
创建享元工厂
- public class BoxFactory {
- private static BoxFactory boxFactory = new BoxFactory();
- //工厂使用单例模式
- public static BoxFactory getInstance(){
- return boxFactory;
- }
-
- private Map
map; -
- public BoxFactory() {
- map = new HashMap<>();
- map.put("I",new IBox());
- map.put("L",new LBox());
- map.put("O",new OBox());
- }
-
- public AbstractBox getBox(String key){
- return map.get(key);
- }
- }
测试
- public class Client {
- public static void main(String[] args) {
- BoxFactory factory = BoxFactory.getInstance();
- AbstractBox IBox = factory.getBox("I");
- IBox.getColor("绿色");
- AbstractBox LBox = factory.getBox("L");
- LBox.getColor("白色");
- AbstractBox LBox2 = factory.getBox("L");
- LBox2.getColor("黑色");
- System.out.println(LBox==LBox2);
- }
- }
形状为:I,颜色为:绿色
形状为:L,颜色为:白色
形状为:L,颜色为:黑色
true
根据运行结果可以看出来外部状态(颜色)的改变不会影响共享。
为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,使程序逻辑复杂
Integer类中的ValueOf()方法就使用到了享元模式
- public class Demo {
- public static void main(String[] args) {
- Integer i1 = 127;
- Integer i2 = 127;
-
- System.out.println(i1 == i2);
-
- Integer i3 = 128;
- Integer i4 = 128;
-
- System.out.println(i3 == i4);
- }
- }
ture
false
由结果可以看到这里产生了两种不同的结果,对于int类型的引用变量,装箱为Integer类型的对象,使用的是ValueOf()方法,查看ValueOf源码

这里可以看到,对于传过来的参数有一个判断操作,点进去IntegerCache查看对应的low与high属性是什么
- 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() {}
- }



这个静态类初始化low为-128以及定义一个high属性以及一个Integer类型的cache数组。
读取官方注释,我们可以猜测出,high属性的值可以在初始化JVM时进行更改。在静态代码块做的事情就是判断high的值是否有设置,如果没有更改就不进行if判断对h的值进行修改,如果修改了high属性值,则要进行判断是否将设置的值对h进行替换作为high属性。
对high进行完赋值后,初始化cache数组,数组长度为最大值与最小值的范围长度。然后通过for循环对范围内的所有值创建成Integer对象存放在数组中
在客户端使用时,先进行判断数组中是否存在了这个数的对象,如果存在直接返回即可,如果不存在则要进行创建Integer对象返回。