学习笔记——JAVA设计模式<1>单例模式

来源:互联网 发布:电脑设计绘图软件 编辑:程序博客网 时间:2024/06/04 07:41

Group of four
GFO23种设计模式
创建型模式建对象
单例模式 工厂模式 抽象工厂模式 建造者模式原型模式
结构性模式
适配器模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式
行为模式
横版方法模式 命令模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 访问者模式

单例模式
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
优点:内存占用 系统开销小。可以在系统设置全局访问点,优化共享资源的访问,例如可以设计一个单例类,负责所有数据表的映射处理
五种实现方式 主要:1·饿汉式(线程安全,调用效率高。不能延时加载)2·懒汉式(线程安全,调用效率不高。可以延时加载) 其他:3·双重检查锁式(由于jvm底层内部模型原因,偶尔会出问题。不建议使用) 4·静态内部类式(线程安全,调用效率高。可以延时加载) 5·枚举单例(线程安全,调用效率高。不能延时加载)

饿汉式的实现
线程安全,调用效率高。不能延时加载

package studyGFO;/** * 测试饿汉式单例模式 * @author http://blog.csdn.net/thewaiting * */public class SingLetonDome {    //由于加载类时线程安全 方法没有同步调用效率高    // 定义static对象 饿汉式 类初始化时       立即加载这个对象(没有延时加载的优势)    private static SingLetonDome instance = new SingLetonDome();    // 私有构造器    private SingLetonDome() {    }    //建立方法返回对象 如果始终没有调用这个方法那就造成资源的浪费    public static SingLetonDome getInstance() {        return instance;    }}

懒汉式的实现
线程安全,调用效率不高。可以延时加载

package studyGFO;/** * 测试懒汉式单例模式 * @author http://blog.csdn.net/thewaiting * */public class SingLetonDome {        // 定义static对象 不初始化对象 延时加载 用时加载        private static SingLetonDome instance;        // 私有构造器        private SingLetonDome() {        }        //建立方法返回对象 资源利用率高。但是调用时要同步并发效率低        public static synchronized SingLetonDome getInstance() {            if (instance == null) {                instance = new SingLetonDome();            }            return instance;        }}

双重检测锁的实现
由于jvm底层内部模型原因,偶尔会出问题。不建议使用

静态内部类的实现(也是一种懒加载方式)
外部类没有static属性,则不会像饿汉式那样立即加载对象
只有真正调用getInstance(),才会加载静态内部类,加载类时是线程安全的,instance是static final类型,保证了内存中只有这样一个实力存在,而且只能被赋值一次,从而只能被赋值一次,从而保证了线程安全性,
兼并了并发高效调用和延时加载的优势

package studyGFO;/** * 测试静态内部类实现单例模式 * 线程安全 调用效率高 实现延时加载 * @author http://blog.csdn.net/thewaiting * */public class SingLetonDome {    //静态内部类    private static class SingLetonClassInstance{        private static final SingLetonDome instance = new SingLetonDome();    }    //私有构造器    private SingLetonDome() {    }    //返回静态内部类里的对象    public static SingLetonDome getInstance() {        return SingLetonClassInstance.instance;    }}

使用枚举的实现
实现简单
枚举本身就是单例模式。由jvm从根本上提供保障!避免通过反射和序列化的漏洞
无延时加载

package studyGFO;/** * 测试枚举实现单例模式 * 没有延时加载 * @author http://blog.csdn.net/thewaiting * */public enum SingLetonDome {     //这个枚举元素,本身就是单例对象    INSTANCE;    //添加自己需要的操作    public void myMethon() {    }}    //调用    public static void main(String[] args) {        System.out.println(SingLetonDome.INSTANCE);    }

如何选用
单例对象 占用资源少,不需要延时加载
枚举式 好于 饿汉式
单例对象 占用资源大,需要延时加载
静态内部类式 好于 懒汉式

通过反射和反序列化破解单例模式不包括枚举(安全)

反射

package studyGFO;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;/** * 测试反射和反序列化破解但单例模式 * @author http://blog.csdn.net/thewaiting * */public class Client {    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,     SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {        SingLetonDome singLetonDome = SingLetonDome.getInstance();        SingLetonDome singLetonDome2 = SingLetonDome.getInstance();        System.out.println(singLetonDome);        System.out.println(singLetonDome2);        Class<SingLetonDome> clazz = (Class<SingLetonDome>) Class.forName("studyGFO.SingLetonDome");        Constructor<SingLetonDome> constructor = clazz.getDeclaredConstructor(null);        //跳过检查        constructor.setAccessible(true);        SingLetonDome s3 = constructor.newInstance();        System.out.println(s3);    }}运行结果studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@6d06d69c

修改

package studyGFO;import javax.management.RuntimeErrorException;/** * 测试懒汉式单例模式(如何防止反射和反序列化漏洞) * @author http://blog.csdn.net/thewaiting * */public class SingLetonDome {        // 定义static对象 不初始化对象 延时加载 用时加载        private static SingLetonDome instance;        // 私有构造器        private SingLetonDome() {            //修改  再次运行就有异常了            if (instance != null) {                throw new RuntimeException();            }        }        //建立方法返回对象 资源利用率高。但是调用时要同步并发效率低        public static synchronized SingLetonDome getInstance() {            if (instance == null) {                instance = new SingLetonDome();            }            return instance;        }}

反序列化

package studyGFO;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutput;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;/** * 测试反射和反序列化破解但单例模式 * @author http://blog.csdn.net/thewaiting * */public class Client {    public static void main(String[] args)            throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException,            IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {        SingLetonDome singLetonDome = SingLetonDome.getInstance();        SingLetonDome singLetonDome2 = SingLetonDome.getInstance();        System.out.println(singLetonDome);        System.out.println(singLetonDome2);        //通过反序列化方式构造多个对象        //序列化        FileOutputStream fos = new FileOutputStream("d:/a.txt");        ObjectOutputStream oos = new ObjectOutputStream(fos);        oos.writeObject(singLetonDome);        oos.close();        fos.close();        //反序列化        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));        SingLetonDome s4 = (SingLetonDome) ois.readObject();        System.out.println(s4);    }}运行结果studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@4c873330

修改代码

package studyGFO;import java.io.ObjectStreamException;import java.io.Serializable;/** * 测试懒汉式单例模式(如何防止反序列化漏洞) * @author http://blog.csdn.net/thewaiting * */public class SingLetonDome implements Serializable{        // 定义static对象 不初始化对象 延时加载 用时加载        private static SingLetonDome instance;        // 私有构造器        private SingLetonDome() {        }        //建立方法返回对象 资源利用率高。但是调用时要同步并发效率低        public static synchronized SingLetonDome getInstance() {            if (instance == null) {                instance = new SingLetonDome();            }            return instance;        }        //修改 反序列化  如果定义了readResolve()则直接返回此方法的指定对象        private Object readResolve() throws ObjectStreamException{            return instance;                    }}运行结果studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@15db9742studyGFO.SingLetonDome@15db9742
原创粉丝点击