zoukankan      html  css  js  c++  java
  • effective解读-第三条 构建单例

    单例:实例化一次的类,例如Spring容器通过IOC构建的Bean默认为单例模式

    实现单例的方式

    1. 静态域

    优势:1. API简单清晰 2.简单(代码少,容易理解)

    缺点:预防反射攻击和提供序列化需要更多代码的支持

    public class SingletonInstance {
        public static final SingletonInstance singletonInstance=new SingletonInstance();
        private SingletonInstance(){
        }
        public void method(){
            System.out.println(this);
        }
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //创建实例
            SingletonInstance singletonInstance = SingletonInstance.singletonInstance;
            //反射创建实例
            SingletonInstance.singletonInstance.method();
            Constructor constructor = SingletonInstance.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            SingletonInstance o = (SingletonInstance) constructor.newInstance();
            //结果为false,即该方式可能被AccessibleObject.setAccessible方式攻击
            System.out.println(o==singletonInstance);
        }
    }

    解决办法

    /**
     * @author Programmer_Liu.
     * @since 2021/3/25 16:32
     */
    public class SingletonInstance {
        private static  boolean flag = true;
        public static final SingletonInstance singletonInstance = new SingletonInstance();
        private SingletonInstance() {
            if (flag){
                flag = false;
            }else{
                throw new RuntimeException("重复构建对象");
            }
        }
    ​
        public void method() {
            System.out.println(this);
        }
    }
    class Main{
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            SingletonInstance singletonInstance = SingletonInstance.singletonInstance;
            SingletonInstance.singletonInstance.method();
            Constructor constructor = SingletonInstance.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            SingletonInstance o = (SingletonInstance) constructor.newInstance();
            System.out.println(o == singletonInstance);
        }  
    }

    支持序列化

    1. 实现序列化接口

    2. 提供readResolve()方法

    public class SingletonInstance implements Serializable {
        private static  boolean flag = true;
        public static final SingletonInstance singletonInstance = new SingletonInstance();
        private SingletonInstance() {
            if (flag){
                flag = false;
            }else{
                throw new RuntimeException("重复构建对象");
            }
        }
        public void method() {
            System.out.println(this);
        }
    ​
        /**
         *保证反序列化单例的唯一
         */
        public Object readResolve(){
            return singletonInstance;
        }
    }
    class Main{
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException {
            SingletonInstance singletonInstance = SingletonInstance.singletonInstance;
            SingletonInstance.singletonInstance.method();
            //Constructor constructor = SingletonInstance.class.getDeclaredConstructor();
            //constructor.setAccessible(true);
            //SingletonInstance o = (SingletonInstance) constructor.newInstance();
            //System.out.println(o == singletonInstance);
            //序列化
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\Users\管理员\Desktop\objectFile.obj"));
            out.writeObject(singletonInstance);
    ​
            //反序列化
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("C:\Users\管理员\Desktop\objectFile.obj"));
            SingletonInstance singletonInstance1 = (SingletonInstance)in.readObject();
            //反序列化
            ObjectInputStream in2 = new ObjectInputStream(new FileInputStream("C:\Users\管理员\Desktop\objectFile.obj"));
            SingletonInstance singletonInstance2 = (SingletonInstance)in2.readObject();
            System.out.println(singletonInstance2==singletonInstance1);
        }
    }

    2.静态工厂方式

    优势:相比静态域的方式更灵活 1.不改变API的前提下可以改为每个线程返回唯一实例2.可以编写泛型类型3.使用者可以使用方法引用

    至少需要上面的优势之一,否则应该有限考虑静态域的方式

    缺点:比较复杂而且预防反射攻击和提供序列化需要更多代码的支持

    //静态工厂方式的单例模式
    public class SingletonInstance {
        private static  boolean flag = true;
        private static final SingletonInstance singletonInstance = new SingletonInstance();
        private SingletonInstance() {
            if (flag){
                flag = false;
            }else{
                throw new RuntimeException("重复构建对象");
            }
        }
        public static SingletonInstance getInstance(){
            return singletonInstance;
        }
        public void method() {
            System.out.println(this);
        }
    ​
    }
    class Main{
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            SingletonInstance singletonInstance = SingletonInstance.getInstance();
            singletonInstance.method();
        }
    }

    1.线程单例

    public class SingletonInstance {
        private static ThreadLocal<Boolean> flag = ThreadLocal.withInitial(() -> Boolean.TRUE);
        private static final ThreadLocal<SingletonInstance> LOCAL = ThreadLocal.withInitial(SingletonInstance::new);
        private SingletonInstance() {
            if (flag.get()) {
                flag.set(false);
            } else {
                throw new RuntimeException("重复构建对象");
            }
        }
    ​
        public static SingletonInstance getInstance() {
            SingletonInstance singletonInstance = LOCAL.get();
            return singletonInstance;
        }
    ​
        public void method() {
            System.out.println(this);
        }
    ​
    }
    ​
    class Main {
        public static void main(String[] args) throws InterruptedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            SingletonInstance singletonInstance = SingletonInstance.getInstance();
            singletonInstance.method();
            //Constructor constructor = SingletonInstance.class.getDeclaredConstructor();
            //constructor.setAccessible(true);
            //SingletonInstance o = (SingletonInstance) constructor.newInstance();
            new Thread(() -> {
                SingletonInstance singletonInstance2 = SingletonInstance.getInstance();
                singletonInstance2.method();
            }).start();
            Thread.sleep(2000);
            SingletonInstance singletonInstance3 = SingletonInstance.getInstance();
            singletonInstance3.method();
        }
    }

    2.泛型单例工厂

    //接口
    public interface UnaryFunction<T> {
        T apply(T args);
    }
    //工厂
    public class UnaryFunctionFactory {
        private static UnaryFunction<T> unaryFunction = args -> args;
    ​
        /**
         * 需要返回什么类型就转为什么类型
         * 使用层面:用什么类型接收就转为什么类型
         */
        public static<T> UnaryFunction<T> getInstance(){
            return (UnaryFunction<T>)unaryFunction;
        }
    ​
        public static void main(String[] args) {
            //用Integer类型接收
            UnaryFunction<Integer> s1=UnaryFunctionFactory.getInstance();
            Integer apply = s1.apply(111);
            //用String类型接收
            UnaryFunction<String> s2=UnaryFunctionFactory.getInstance();
            String hello = s2.apply("hello");
        }
    }
    ​

    3.方法引用

    public class SingletonInstance{
        private static boolean flag = true;
        private static final SingletonInstance singletonInstance = new SingletonInstance();
        private SingletonInstance() {
            if (flag) {
                flag = false;
            } else {
                throw new RuntimeException("重复构建对象");
            }
        }
        public static SingletonInstance getInstance() {
            return singletonInstance;
        }
        public void method() {
            System.out.println(this);
        }
    }
    ​
    class Main {
        //提供者接口中可以直接通过方法引用调用
        public SingletonInstance s(Supplier<SingletonInstance> s){
            return s.get();
        }
        public static void main(String[] args){
            Main main = new Main();
            SingletonInstance s = main.s(SingletonInstance::getInstance);
            s.method();
        }
    }

    3. 单元素枚举

    优势:更加简单,内部提供了序列化机制并预防反射攻击。单元素枚举是实现Singleton的最佳方案。

    缺点:无法继承超类,因为枚举类型默认继承了Enum类

     

    作者:刘志红

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    数据库之表与表之间的关系
    数据库之完整性约束条件
    基本数据类型
    数据库
    Django ajax 发送post请求 前端报错解决
    Django数据库建立注意事项
    编程单词汇总
    程序员必掌握600单词
    python思维导图
    用jQuery模拟hover选择效果
  • 原文地址:https://www.cnblogs.com/chengxuyuan-liu/p/14581751.html
Copyright © 2011-2022 走看看