Effective Java -- 用私有构造器或者枚举类型强化Singleton属性

本文是 《Effective Java》第三条的读书笔记,由于是Java进阶书,难免会有理解的偏差,如有错误,非常欢迎能批评指正,本人不胜感激!


首先介绍两种常见的实现Singleton的方法

在这两个方法中,都需要把构造函数设置为私有private的,并导出该类的公有静态成员。

第一种方法中,公有静态成员是该类的实例(并且是final的),如下

class UserInfo{
    public static final UserInfo userInfo = new UserInfo();
    private UserInfo(){
        // 用户通过反射机制再次创建实例,则抛异常(先不用理解,后面有说到)
        if(UserInfo.userInfo!=null){
            throw new RuntimeException("不能创建多个对象");
        }
    }
}

这样在客户端直接通过如下代码即可获取实例(单例的)

UserInfo userInfo=UserInfo.userInfo;

第二种方法中,公有的成员是静态工厂方法,该方法返回该类的静态的final的实例,如下

class UserInfo{
    private static final UserInfo userInfo = new UserInfo();
    private UserInfo(){
        // 用户通过反射机制再次创建实例,则抛异常(先不用理解,后面有说到)
        if(UserInfo.userInfo!=null){
            throw new RuntimeException("不能创建多个对象");
        }
    }
    public static UserInfo getInstance(){
        return UserInfo.userInfo;
    }
}

客户端的代码如下

UserInfo userInfo=UserInfo.getInstance();

但是上面的两个方法都会存在一个问题,如果我们通过Java的反射机制调用私有构造器则就会生成两个实例了

如果该构造函数被调用超过一次,我们可以在该对象的构造函数中抛出异常,如上面构造函数中的代码

        if(UserInfo.userInfo!=null){
            throw new RuntimeException("不能创建多个对象");
        }

我们利用Java反射机制来测试一下

package com.blog.effective3;

import java.lang.reflect.Constructor;

/**
 * @func 用私有构造器或者枚举类型强化Singleton属性.
 * @author 张俊强~
 * @time 2017/10/30 21:00
 */
public class EffectiveJavaDemoOne {

    public static void main(String[] args) throws Exception{
        UserInfo userInfo=UserInfo.userInfo;
        System.out.println(userInfo);

        // 第利用反射机制调用私有构造函数
        Class class1 = Class.forName("com.blog.effective3.UserInfo");
        // 得到构造函数
        Constructor con = class1.getDeclaredConstructor();
        con.setAccessible(true);
        UserInfo userInfo1=(UserInfo) con.newInstance();//再次创建一个实例
    }

}

class UserInfo{
    public static final UserInfo userInfo = new UserInfo();
    private UserInfo(){
        // 用户通过反射机制再次创建实例,则抛异常
        if(UserInfo.userInfo!=null){
            throw new RuntimeException("不能创建多个对象");
        }
    }
}

代码抛出如下异常

Caused by: java.lang.RuntimeException: 不能创建多个对象
    at com.blog.effective3.UserInfo.(EffectiveJavaDemoOne.java:33)
    ... 10 more

实现Singleton的第三种方法这时候就登场了
其表现形式更加的简洁,无偿的提供了序列化机制,绝对的防止了多次实例化。
这种方式就是:单元素的枚举类型——实现Singleton的最佳方法。

enum StudentInfo{
    STUDENT_INFO;
}

客户端的代码如下

StudentInfo studentInfo=StudentInfo.STUDENT_INFO;

有关该章节中提到的序列化部分,本人了解不是非常的深入,故//TODO 以后再完善相关部分。

参考资料
[1].用私有构造器或者枚举类型强化Singleton属性


2017/10/30 21:58 于福州大学.

你可能感兴趣的:([,Effective,Java,Notes,],Effective,Java,Notes)