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

单实例模式在Java中主要的创建方式

参考博客:

第一种:使用公有静态成员,并且是final域

公有静态成员是一个final域,对于以下示例,私有构造器仅被调用一次,用来实例化公有的静态final域Elvis.INSTANCE。
由于缺少公有的或者受保护的构造器(我们从示例可看出,只有上文提到的那个私有构造器),所以保证了Elvis的全局唯一性。
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() {
    }

    public void leaveTheBuilding() {
        System.out.println("Please leave the Building!");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

第二种:使用公有静态成员方法去返回单实例对象---【静态工厂方法】

对于静态方法Elvis.getInstance的所有调用,都会返回同一个对象引用,所以,能保证创建单实例对象,永远不会创建其他的Elvis实例。
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() {
    }
    
    public static Elvis getInstance() {
        return INSTANCE;
    }
    
    public void leaveTheBuilding() {
        System.out.println("Please leave the Building!");
    }
    
    public static void main(String[] args) {
        Elvis elvis = Elvis.getInstance();
        elvis.leaveTheBuilding();
    }
}

但是这种方法可以很容易的被修改成按不同需求返回相应的唯一实例。

上述两种方法都存在的问题
享有特权的客户端可能借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器,这样就破坏了Singleton。如果要抵御这种攻击,可以修改构造器让它在被要求创建第二个实例的时候抛出异常。
private static int count = 0;  //添加次数变量
    private static final Student INSTANCE = new Student();
    
    // 修改私有构造器
    private Student() {
    	if (count > 0) {
            throw new IllegalArgumentException(
                    "Error,Cannot create Student twice!");
        }
        count++;
    }

第三种:声明一个包含单个元素的枚举类型----【实现Singleton的最佳方法】

注意:如果Singleton必须扩展一个超类,而不是扩展Enum的时候,则不宜使用这个方法。(虽然可以声明枚举去实现接口)
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() {
        System.out.println("Please leave the Building!");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}
----END