zoukankan      html  css  js  c++  java
  • 创建者模式 -- 单例模式(反射&序列化)

    看的视频:https://www.bilibili.com/video/av43896218/?p=286

    实现方式:(构造器私有,提供一个外部可以访问的方法(可以提供实例)

    1、饿汉式:线程安全,调用效率高, 不能延时加载

    2、懒汉式:线程安全,调用效率不高,可以延时加载(要用的时候才加载  )

    3、双重锁检测式:“由于JVM底层内部模型原因,偶尔会出现问题,不建议使用”

    4、静态内部类式:线程安全,调用效率高,且可以实现延时加载

    (上面的四种方式都可以通过反射和反序列化 破坏 单例模式)

    5、枚举:线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化

    如果单例对象占用资源少,不需要延时加载:

    枚举式 优于 饿汉式

    如果单例对象占用资源大, 需要延时加载:

    静态内部类式 优于 懒汉式 

    饿汉式:

    /*
    饿汉式: 最开始就已经把实例给创建好了
     */
    public class Singleton01 {
        public static Singleton01 instance = new Singleton01();  //一开始就已经创建好了
        private Singleton01(){
        }
        public static Singleton01 getInstance(){
            return instance;
        }
    }

    懒汉式:

    /*
    懒汉式: 用的时候才会初始化实例   效率不高就是因为有synchronized这个关键字
     */
    public class Singleton02 {
        private static Singleton02 instance = null;
        private Singleton02(){
        }
        public static synchronized Singleton02 getInstance(){
            if(instance == null){
                instance = new Singleton02();
            }
            return instance;
        }
    }

    静态内部类:

    /*
    静态内部类: 只有在主动调用这个类的时候才会加载   外部类加载的时候 静态内部类不会加载
     */
    public class Singleton03 {
        static class Inner{
            private static Singleton03 instance = new Singleton03();
        }
        private Singleton03(){
    
        }
        public static Singleton03 getInstance(){
            return Inner.instance;
        }
    }

    枚举:

    /*
    枚举  天然的可以防止 反射和反序列化
     */
    public enum Singleton04 {
        INSTANCE; //就表示一个实例 获取的时候直接  Singleton04.INSTANCE 
        public void method(){
            //这里可以写一些方法
        }
    }

    通过反射破坏单例模式:

    public class Test01 {
        public static void main(String[] args) throws Exception{
                Class<?> clazz = Class.forName("com.test.Singleton01");
                //获取构造函数:
                Constructor c = clazz.getDeclaredConstructor();
                c.setAccessible(true); //对于私有属性和方法 设置为允许访问
                //通过构造函数 构造实例
                Singleton01 singleton001 = (Singleton01)c.newInstance();
                Singleton01 singleton002 = (Singleton01)c.newInstance();
                System.out.println(singleton001 == singleton002);  // false
        }
    }

    如何破坏反射:

    public class Singleton01 {
        private static boolean  flag = false; //标志位
        public static Singleton01 instance = new Singleton01();  //一开始就已经创建好了
        // 上面的已经调用过一次 这个私有的构造函数了

    private Singleton01(){ //反射的时候操作的就是这个私有的构造函数 synchronized (Singleton01.class){ if(flag == false){ flag = true; }else{ //表示第二次用构造函数进行实例化 throw new RuntimeException("单例模式正在被破坏"); } } } public Singleton01 getInstance(){ return instance; } }

    在用反射就会报错....

    通过反序列化破坏单例模式:

     对象序列化:将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或者通过网络发送到任何其他程序中。

     反序列化:将字节流转化为对象的过程。

    public class Test01 {
        public static void main(String[] args) throws Exception{
    //序列化 singleton001 Singleton01要实现 Serializable Singleton01 singleton001 = Singleton01.getInstance(); Singleton01 singleton002 = Singleton01.getInstance(); FileOutputStream fos = new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(singleton001); oos.close(); fos.close(); //反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt")); Singleton01 singleton003 = (Singleton01)ois.readObject(); System.out.println(singleton001 == singleton002); //true System.out.println(singleton001 == singleton003); //false } }

    防止反序列化:

    public class Singleton01 implements Serializable {
        public static Singleton01 instance = new Singleton01();  //一开始就已经创建好了
        private Singleton01(){
        }
        public static Singleton01 getInstance(){
            return instance;
        }
        //在反序列化的时候  直接调用这个方法 返回instance   而不是返回反序列化后的新对象
        private Object readResolve() throws ObjectStreamException {
            return instance;
        }
    }
  • 相关阅读:
    Qt:QT右键菜单
    Ubuntu 12.04安装字体
    在ubuntu下关闭笔记本触摸板
    SSL与TLS的区别以及介绍
    隔行扫描与逐行扫描的区别
    Linux下的绘图(流程图、UML、mindmap)工具
    RedHat Linux 下安装MPlayer 编译源代码方式
    循环数组实现队列的四种方式
    Linux内核spin_lock与spin_lock_irq分析
    Oracle 创建同义词
  • 原文地址:https://www.cnblogs.com/DDiamondd/p/10966745.html
Copyright © 2011-2022 走看看