第三条:用私有构造器或者枚举类型强化Singleton属性

Singleton指仅仅被实例化一次的类,Java1.5之前,实现Singleton有两种方式,这两种方式都要把构造器保持为私有的,并导出公有的静态成员。

第一种:公有静态成员是个final域

public class Elvis {
    public static final Elvis INSTANCE=new Elvis();
    private Elvis(){};
}

第二种:公有成员方法是一个静态工厂方法:

public class Elvis {
    private static final Elvis instance=new Elvis();
    private Elvis(){};
    
    public static Elvis getInstance(){
        return instance;
    }
}
私有构造器仅被调用一次,用来实例化公有的静态final域Elvis,INSTANCE,由于缺少公有的构造器,所以保证了Elvis的全局唯一性,一旦Elvis被实例化,
只会存在一个Elvis实例,但是客户端可以借助AccessiableObject.setAccessible方法,通过反射机制,调动私有构造器
Elvis elvis1=Elvis.getInstance();
        Class<Elvis> cls=Elvis.class;
        try {
            Constructor<Elvis> constructor=cls.getDeclaredConstructor(new Class[]{});
            constructor.setAccessible(true);
            try {
                Elvis elvis2=constructor.newInstance(new Object[]{});
                System.out.println(elvis1==elvis2);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

最后输出:false

还有一种情况是就是序列化和反序列化的时候也会出现多个不同的实例:

File file = new File("singleton");
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(file));
            Elvis SingletonB1 = Elvis.getInstance();

            oos.writeObject(SingletonB1);
            oos.close();
            ois = new ObjectInputStream(new FileInputStream(file));
            Elvis SingletonB2 = (Elvis) ois.readObject();
            System.out.println(SingletonB1 == SingletonB2);//false

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

输出:false

这个问题可以提供readResolve方法是为了每次反序列化一个序列化的实例时,避免去创建一个新的实例。

public class Elvis implements Serializable {
    private static final Elvis instance=new Elvis();
    private Elvis(){};

    public static Elvis getInstance(){
        return instance;
    }
    // 不添加该方法则会出现 反序列化时出现多个实例的问题
    public Object readResolve() {
        return instance;
    }
}

第三种方式:单元素的枚举类型.

public enum Singletonc implements Serializable {
    INSTANCE;

    private Singletonc() {
    }

    String type;

    public void setType(String name) {
        this.type = name;
    }

    public void getType() {
        System.out.println(type);
    }

    public static void main(String[] args){
        Singletonc.INSTANCE.setType("哈哈哈哈");
        Singletonc.INSTANCE.getType();
    }
}

单元素的枚举类型已经成为实现Singleton的最佳方法

猜你喜欢

转载自blog.csdn.net/qiuhao9527/article/details/80773268
今日推荐