设计模式课程 设计模式精讲 9-3 原型模式-克隆破坏单例

1    代码演练

1.1  克隆破坏单例

1.2  如何防范克隆破坏单例

1.3  小问

1    代码演练
1.1  克隆破坏单例

实体类:

package com.geely.design.pattern.creational.singleton;

import java.io.Serializable;

public class HangrySingleton implements Serializable,Cloneable {


    /**
     * 声明私有常量,当类初始化的时候就已经赋值了。饿汉式在类初始化的时候只加载一次。
     * 所以也不会存在多线程的问题。
     */
    private final static HangrySingleton hangrySingleton;

    static {
        hangrySingleton= new HangrySingleton();
    }

    /**
     * 声明私有构造方法
     * 因为饿汉式和静态类在类初始化的时候,已经附上了对象,反射取值的时候该对象一定有值。
     */
    private HangrySingleton(){
        if(hangrySingleton != null){
            throw new RuntimeException("单例构造器禁止反射!");
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    /**
     * 防止序列化和反序列化对单例模式进行破坏
     */
    private Object readResolve(){
        return hangrySingleton;
    }

    /**
     * 提供对外接口,获得对象
     * @return
     */
    public static HangrySingleton getInstance(){
        return hangrySingleton;
    }
}

测试类:

package com.geely.design.pattern.creational.prototype;

import com.geely.design.pattern.creational.singleton.HangrySingleton;
import sun.reflect.Reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

public class Test2 {
    public static void main(String [] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
           /* Date date1 = new Date();
            Pig pig1 = new Pig("peiqi",date1);
            Pig pig2 = (Pig) pig1.clone();
            System.out.println(pig1);
            System.out.println(pig2);


            //预期修改pig1的生日,没想到pig2的生日也改了
            pig1.getBirthday().setTime(0L);
            System.out.println(pig1);
            System.out.println(pig2);*/


           //如何破坏单例模式?克隆方式破坏单例模式
            HangrySingleton hangrySingleton = HangrySingleton.getInstance();//取得单例对象
            //反射打开方法的权限
            Method method = hangrySingleton.getClass().getDeclaredMethod("clone");
            method.setAccessible(true);
            //克隆方法是protected权限,只有本类或者派生的类中使用,所以需要打开权限
            HangrySingleton hangrySingleton2 = (HangrySingleton) method.invoke(hangrySingleton);
            System.out.println(hangrySingleton);
            System.out.println(hangrySingleton2);

    }
}

打印日志:

"C:\Program Files\Java\jdk1.7.0_79\bin\java.exe" "-javaagent:D:\java\devolopKit\idea\anZh\IntelliJ IDEA Community Edition 2018.1.4\lib\idea_rt.jar=12734:D:\java\devolopKit\idea\anZh\IntelliJ IDEA Community Edition 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_79\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\rt.jar;F:\xiangmu3\Xin\Idea\design_pattern\target\classes" com.geely.design.pattern.creational.prototype.Test2
com.geely.design.pattern.creational.singleton.HangrySingleton@63ce0e18
com.geely.design.pattern.creational.singleton.HangrySingleton@6cff7cd8

Process finished with exit code 0
1.2  如何防范克隆破坏单例

a  单例类不实现克隆接口

b  这样修改

package com.geely.design.pattern.creational.singleton;

import java.io.Serializable;

public class HangrySingleton implements Serializable,Cloneable {


    /**
     * 声明私有常量,当类初始化的时候就已经赋值了。饿汉式在类初始化的时候只加载一次。
     * 所以也不会存在多线程的问题。
     */
    private final static HangrySingleton hangrySingleton;

    static {
        hangrySingleton= new HangrySingleton();
    }

    /**
     * 声明私有构造方法
     * 因为饿汉式和静态类在类初始化的时候,已经附上了对象,反射取值的时候该对象一定有值。
     */
    private HangrySingleton(){
        if(hangrySingleton != null){
            throw new RuntimeException("单例构造器禁止反射!");
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return getInstance();
    }

    /**
     * 防止序列化和反序列化对单例模式进行破坏
     */
    private Object readResolve(){
        return hangrySingleton;
    }

    /**
     * 提供对外接口,获得对象
     * @return
     */
    public static HangrySingleton getInstance(){
        return hangrySingleton;
    }
}
 1.3  小问

有哪些方式能够破坏单例模式呢?

克隆,

自己推测:序列化,反射攻击(可以翻看前边视频,后边有时间了再来巩固)

  

 

猜你喜欢

转载自www.cnblogs.com/1446358788-qq/p/11470779.html