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

Singleton其实就是单例,即一个类在一个应用程序中只被实例化一次,只有一个对象。

本节讨论三种实现方式

  • 私有构造+共有成员
  • 私有构造+静态工厂方法+私有成员
  • 枚举实现

1、共有成员

构造方法私有,有一个该类类型的公有不可变的实例域。

1.1 code

public class Singleton01 {
    
    
    public static final Singleton01 singleton01 = new Singleton01();
    private Singleton01(){
    
    }
}

当类加载的时候就会创建静态域,同时构造函数私有,因此可以保证唯一实例。

客户端调用:

Singleton01 singleton01 = Singleton01.singleton01;

1.2 分析

  • 优点:实现简单;能够明确指导这是一个单例对象,因为公有的静态域时final的,只会存在一个。

  • 缺点:可以利用反射调用私有构造方法而二次创建该对象

2、静态工厂方法

将成员定义为私有,提供一个静态方法,返回对象。同时构造方法私有

2.1 code

public class Singleton02 {
    
    
    /**
     * 私有
     */
    private static final Singleton02 instance = new Singleton02();
    private Singleton02(){
    
    }

    /**
     * 获取唯一的Singleton02实例
     * @return
     */
    public static Singleton02 getInstance(){
    
    
        return instance;
    }
}

对于静态方法getInstance的调用,返回的都是同一个Singleton02实例。

客户端调用:

Singleton02 instance = Singleton02.instance;

2.2 分析

  • 优点:(1)灵活,只需要改变getInstance方法就能修改是否时单例(例如改为每个线程创建一个);(2)可以使用方法引用提供参数,写起来优雅;(3)可以编写范型Singleton工厂,30条在分析。

  • 缺点:和1相比,不明显是单例;没有解决反射破坏单例的问题。

注意:

上述两种方法,出了反射调用私有构造方法破坏单例外,反序列化也会破坏单例,针对反序列化的问题,可以声明实例域是瞬时的,并提供一个 readResolves,这点在第89条讨论。

private static final transient Singleton02 instance = new Singleton02();

3、使用枚举

将想要单例的类定义为一个枚举类型

3.1 code

public enum Singleton03 {
    
    
    INSTANCE("zhangsan","male");

    private String name;
    private String gender;

    Singleton03(String name, String gender) {
    
    
        this.name = name;
        this.gender = gender;
    }
}

客户端使用:

Singleton03 instance = Singleton03.INSTANCE;

3.2 分析

  • 优点:安全,枚举的内部实现就禁用了反射和反序列机制。

  • 缺点:如果单例类必须扩展一个超类,这时候就不适用了。因为枚举不能继承其他类。

猜你喜欢

转载自blog.csdn.net/baidu_40120883/article/details/131870931