11.单例模式(超详细版本)

1.什么是单例?
2.单例有哪些实现方式
3.单例模式优缺点
4.懒汉式、饿汉式区别
5.反射如何破解单例?
6.单例如何防止反射破解
7.枚举为何是最安全的单例模式
8.反射为何破解不了枚举?
9.序列化为什么破解不了枚举
10.如何修改JDK源码破解单例

单例模式

什么是单例模式:jvm中该对象只有一个实例的存在。

class Mayikt{

}

Mayikt mayikt1= New Mayikt(); // 堆内存开辟一块空间

Mayikt mayikt2= New Mayikt(); // 堆内存开辟一块空间

多例

单例模式 缺点:多个线程共享到同一个实例 发生线程安全性问题

单例应用场景

\1. 项目中定义的配置文件

\2. Servlet对象默认就是单例 考虑线程安全

\3. 线程池、数据库连接池

\4. Spring中Bean对象默认就是单例

\5. 实现网站计数器

\6. Jvm内置缓存框架(定义单例HashMap)

\7. 枚举(单例—最安全单例)

单例优缺点

1.优点:能够节约当前堆内存空间,不需要频繁New对象,能够快速访问;

2.缺点:当多个线程访问同一个单例对象的时候可能会存在线程安全问题;

单例模式特点

1、构造方法私有化;

2、实例化的变量引用私有化;

3、获取实例的方法共有。

单例的(7种)写法

\1. 懒汉式线程不安全

\2. 懒汉式线程安全

\3. 懒汉式双重检验锁

\4. 饿汉式

\5. 静态代码块

\6. 静态内部类

\7. 枚举实现单例

懒汉式线程不安全

懒汉式基本概念:当真正需要获取到该对象时,才会创建该对象 该写法存在线程安全性问题

public class Singleton01 {
    //实例化的变量引用私有化
    private static Singleton01 singleton = null;

    /**
     * 私有化构造函数
     */
    private Singleton01() {

    }

    public static Singleton01 getSingleton() {
        if (singleton == null) {
            singleton = new Singleton01();
        }
        return singleton;
    }

    public static void main(String[] args) {
        Singleton01 singleton1 = Singleton01.getSingleton();
        Singleton01 singleton2 = Singleton01.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}

懒汉式线程安全

public class Singleton02 {
    //实例化的变量引用私有化
    private static Singleton02 singleton = null;

    /**
     * 私有化构造函数
     */
    private Singleton02() {

    }

    //  创建和读取对象都需要获取Singleton01 锁
    public static synchronized Singleton02 getSingleton() {
        if (singleton == null) {
            singleton = new Singleton02();
        }
        return singleton;
    }

    public static void main(String[] args) {
        Singleton02 singleton1 = Singleton02.getSingleton();
        Singleton02 singleton2 = Singleton02.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}

懒汉式双重检验锁

懒汉式:懒加载当我们真正需要该对象时才会创建该对象节约内存

懒汉式双重检验锁--------

缺点:使用该单例对象需要保证线程安全性问题

public class Singleton03 {
    //实例化的变量引用私有化
    private static volatile Singleton03 singleton = null;

    /**
     * 私有化构造函数
     */
    private Singleton03() {

    }

 
    public static Singleton03 getSingleton() {
        if (singleton == null) {
            synchronized (Singleton03.class) {
                if (singleton == null) {
                    singleton = new Singleton03();
                }
            }
        }
        return singleton;
    }

    public static void main(String[] args) {
        Singleton03 singleton1 = Singleton03.getSingleton();
        Singleton03 singleton2 = Singleton03.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}
  */
    public static Singleton03 getSingleton() {

        synchronized (Singleton03.class) {
            if (singleton == null) {// 竞争锁 可能多个线程 同时竞争锁 为避免 单线程重复 new 对象
                singleton = new Singleton03();
            }
        }
        // 多个线程 判断singleton 不为空的情况下 则不需要竞争锁的
        return singleton;
    }

饿汉式

提前创建单例对象,优点先天性保证线程安全,比较占用内存

public class Singleton04 {
    // 当我们class被加载时,就会提前创建singleton对象
    private static Singleton04 singleton = new Singleton04();

    /**
     * 私有化构造函数
     */
    private Singleton04() {

    }

    public static Singleton04 getSingleton() {
        return singleton;
    }

    public static void main(String[] args) {
        Singleton04 singleton1 = Singleton04.getSingleton();
        Singleton04 singleton2 = Singleton04.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}

静态代码块

public class Singleton05 {
    // 当我们class被加载时,就会提前创建singleton对象
    private static Singleton05 singleton = null;

    static {
        singleton = new Singleton05();
        System.out.println("static执行");
    }

    /**
     * 私有化构造函数
     */
    private Singleton05() {

    }

    public static Singleton05 getSingleton() {
        return singleton;
    }

    public static void main(String[] args) {
        Singleton05 singleton1 = Singleton05.getSingleton();
        Singleton05 singleton2 = Singleton05.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}

静态内部类

public class Singleton06 {

    /**
     * 私有化构造函数
     */
    private Singleton06() {

    }

    private static class SingletonHolder {
        private static Singleton06 singleton = new Singleton06();
    }

    public static Singleton06 getSingleton() {
        return SingletonHolder.singleton;
    }

    public static void main(String[] args) {
        Singleton06 singleton1 = Singleton06.getSingleton();
        Singleton06 singleton2 = Singleton06.getSingleton();
        System.out.println(singleton1 == singleton2);
    }
}

枚举单例

枚举属于目前最安全的单例,不能够被反射序列化 破解 保证单例

public enum Singleton03 {
    INSTANCE;

    public void getInstance() {
        System.out.println("<<<getInstance>>>");
    }
}

创建对象的方式有哪些

1.直接new对象

2.采用克隆对象

3.使用反射创建对象

4.序列化与反序列化

单例 是可以 被 反射、序列化 破解 违背了我们

单例模式的设计原则?

反射破解单例

反射破解单例

package com.mayikt.singleton;

/**
* @author 余胜军
* @ClassName Singleton01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Singleton01 {
    private static Singleton01 singleton01;
    
    static {
        try {
            singleton01 = new Singleton01();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private Singleton01() throws Exception {
       
    }
    
    public static Singleton01 getSingleton() {
        return singleton01;
    }
    
    
}
        Singleton01 singleton1 = Singleton01.getSingleton();
        Singleton01 singleton2 = Singleton01.getSingleton();
        System.out.println(singleton1 == singleton2);
        Class<?> aClass = Class.forName("com.mayikt.singleton.Singleton01");
        Constructor<?> constructor = aClass.getDeclaredConstructor();
        // 使用无参构造方法 调用初始化对象
        constructor.setAccessible(true);
        Singleton01 singleton03 = (Singleton01) constructor.newInstance();
        System.out.println(singleton03 == singleton2);

true

false

如何防止反射单例被破解

在构造方法中 判断处理 如果该对象已经有值的情况下 无法重复的创建该对象,

直接抛出异常。

package com.mayikt.singleton;

/**
 * @author 余胜军
 * @ClassName Singleton01
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public class Singleton01 {
    private static Singleton01 singleton01;

    static {
        try {
            singleton01 = new Singleton01();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Singleton01() throws Exception {
        if (singleton01 != null) {
            // 主动抛出异常
            throw new Exception("该对象为单例对象,不能够重复创建");
        }
    }

    public static Singleton01 getSingleton() {
        return singleton01;
    }


}
D:\path\jdk\jdk8\jdk\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:54504,suspend=y,server=n -javaagent:C:\Users\mayikt\AppData\Local\JetBrains\IntelliJIdea2020.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\path\jdk\jdk8\jdk\jre\lib\charsets.jar;D:\path\jdk\jdk8\jdk\jre\lib\deploy.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\access-bridge-64.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\cldrdata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\dnsns.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jaccess.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jfxrt.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\localedata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\nashorn.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunec.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunjce_provider.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunmscapi.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunpkcs11.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\zipfs.jar;D:\path\jdk\jdk8\jdk\jre\lib\javaws.jar;D:\path\jdk\jdk8\jdk\jre\lib\jce.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfr.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfxswt.jar;D:\path\jdk\jdk8\jdk\jre\lib\jsse.jar;D:\path\jdk\jdk8\jdk\jre\lib\management-agent.jar;D:\path\jdk\jdk8\jdk\jre\lib\plugin.jar;D:\path\jdk\jdk8\jdk\jre\lib\resources.jar;D:\path\jdk\jdk8\jdk\jre\lib\rt.jar;D:\data\mayikt-designmode\mayikt-single\target\classes;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-web\2.2.3.RELEASE\spring-boot-starter-web-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter\2.2.3.RELEASE\spring-boot-starter-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot\2.2.3.RELEASE\spring-boot-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-autoconfigure\2.2.3.RELEASE\spring-boot-autoconfigure-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-logging\2.2.3.RELEASE\spring-boot-starter-logging-2.2.3.RELEASE.jar;D:\maven\mvnRespo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\mvnRespo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\mvnRespo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\mvnRespo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\mvnRespo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\mvnRespo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-json\2.2.3.RELEASE\spring-boot-starter-json-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-tomcat\2.2.3.RELEASE\spring-boot-starter-tomcat-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-validation\2.2.3.RELEASE\spring-boot-starter-validation-2.2.3.RELEASE.jar;D:\maven\mvnRespo\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\maven\mvnRespo\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\maven\mvnRespo\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\maven\mvnRespo\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\maven\mvnRespo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;D:\maven\mvnRespo\com\alibaba\fastjson\1.2.73\fastjson-1.2.73.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-starter\1.1.1\mybatis-spring-boot-starter-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\1.1.1\mybatis-spring-boot-autoconfigure-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\mybatis\3.4.0\mybatis-3.4.0.jar;D:\maven\mvnRespo\org\mybatis\mybatis-spring\1.3.0\mybatis-spring-1.3.0.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-jdbc\2.2.3.RELEASE\spring-boot-starter-jdbc-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\zaxxer\HikariCP\3.4.2\HikariCP-3.4.2.jar;D:\maven\mvnRespo\org\springframework\spring-jdbc\5.2.3.RELEASE\spring-jdbc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-tx\5.2.3.RELEASE\spring-tx-5.2.3.RELEASE.jar;D:\maven\mvnRespo\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;D:\maven\mvnRespo\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\idea-mayikt\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar" com.mayikt.test.Test01
Connected to the target VM, address: '127.0.0.1:54504', transport: 'socket'
true
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mayikt.test.Test01.main(Test01.java:24)
Caused by: java.lang.Exception: 该对象为单例对象,不能够重复创建
	at com.mayikt.singleton.Singleton01.<init>(Singleton01.java:24)
	... 5 more
Disconnected from the target VM, address: '127.0.0.1:54504', transport: 'socket'

Process finished with exit code 1

序列化破解单例

序列化破解单例

序列化概念:将对象转换成二进制的形式直接存放在本地 将该对象持久化存放到硬盘中—json 将对象转化成json—序列化

反序列化概念:从硬盘读取二进制变为对象 json 将该json转化成对象—反序列化

package com.mayikt.singleton;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * @author 余胜军
 * @ClassName Singleton01
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public class Singleton02 implements Serializable {
    private static Singleton02 singleton = new Singleton02();

    private Singleton02() {

    }

    public static Singleton02 getSingleton() {
        return singleton;
    }

}


package com.mayikt.test;

import com.mayikt.singleton.Singleton02;

import java.io.*;

/**
 * @author 余胜军
 * @ClassName Test02
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1.将对象序列化存入到本地文件中
        FileOutputStream fos = new FileOutputStream("D:\\mayikt/a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Singleton02 singleton1 = Singleton02.getSingleton();
        oos.writeObject(singleton1);
        oos.close();
        fos.close();
        System.out.println("----------从硬盘中反序列化对象到内存中------------");
        //2.从硬盘中反序列化对象到内存中
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\mayikt/a.txt"));
        // 从新获取一个新的对象
        Singleton02 singleton2 = (Singleton02) ois.readObject();
        System.out.println(singleton1 == singleton2);
    }
}

Connected to the target VM, address: ‘127.0.0.1:58074’, transport: ‘socket’

----------从硬盘中反序列化对象到内存中------------

false

Disconnected from the target VM, address: ‘127.0.0.1:58074’, transport: ‘socket’

Process finished with exit code 0

反序列化 得到我们对象 是否走构造方法----没有呢

如何防止序列化单例被破解

重写readResolve方法 返回原来对象即可

 private Object readResolve() throws ObjectStreamException {
     return singleton;
   }

package com.mayikt.singleton;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * @author 余胜军
 * @ClassName Singleton01
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public class Singleton02 implements Serializable {
    private static Singleton02 singleton = new Singleton02();

    private Singleton02() {

    }

    public static Singleton02 getSingleton() {
        return singleton;
    }

    private Object readResolve() throws ObjectStreamException {
        return singleton;
    }
}

原理:

\1. 调用readObject()

\2. 执行readObject0();

\3. Switch 判断tc=115 object class

img

判断反序列化类中如果存在readResolve方法 则通过反射机制调用readResolve方法返回相同的对象

if (obj != null &&
    handles.lookupException(passHandle) == null &&
    desc.hasReadResolveMethod())
    // 反射判断单例类种是否有ReadResolve
{
    // 使用反射机制调用ReadResolve 得到单例对象
    Object rep = desc.invokeReadResolve(obj);
    if (unshared && rep.getClass().isArray()) {
        rep = cloneArray(rep);
    }
    if (rep != obj) {
        // Filter the replacement object
        if (rep != null) {
            if (rep.getClass().isArray()) {
                filterCheck(rep.getClass(), Array.getLength(rep));
            } else {
                filterCheck(rep.getClass(), -1);
            }
        }
        //在将单例对象赋值给我们的object 
        handles.setObject(passHandle, obj = rep);
    }
        }
return obj// 单例对象。

为什么枚举是最安全的单例

枚举底层就是我类 底层数组封装。

枚举底层就是 java类封装 继承了我们枚举Enum

为什么底层需要继承枚举Enum类

jdk底层需要知道该类是为我们的枚举类

枚举类中是没有无参构造放的…

只有有参构造方法

枚举为什么反射无法破解了,这是因为 jdk底层

反射有判断处理

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException(“Cannot reflectively create enum objects”);
ConstructorAccessor ca = constructorAccessor; // read volatile

如果该类是为枚举类则无法反射初始化

枚举单例不可被反射和序列化

package com.mayikt.singleton;

public enum Singleton05 {
    INSTANCE;

    public void getInstance() {
        System.out.println("<<<getInstance>>>");
    }
}

反射攻击枚举

\1. 使用XJad.exe 反编译枚举 会发现,枚举底层实际上基于类封装的。

img

枚举底层使用类封装的没有无参构造函数所有根据无参构造函数反射会报错

 Singleton03 instance1 = Singleton03.INSTANCE;
 Singleton03 instance2 = Singleton03.INSTANCE;
 System.out.println(instance1 == instance2);
 // 反射攻击枚举
 Class<?> aClass = Class.forName("com.mayikt.singleton.Singleton03");
 Singleton03 instance3 = (Singleton03) aClass.newInstance();
 System.out.println(instance1 == instance3);
---------------------------------------------------------------------------------

D:\path\jdk\jdk8\jdk\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:56436,suspend=y,server=n -javaagent:C:\Users\mayikt\AppData\Local\JetBrains\IntelliJIdea2020.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\path\jdk\jdk8\jdk\jre\lib\charsets.jar;D:\path\jdk\jdk8\jdk\jre\lib\deploy.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\access-bridge-64.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\cldrdata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\dnsns.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jaccess.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jfxrt.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\localedata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\nashorn.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunec.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunjce_provider.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunmscapi.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunpkcs11.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\zipfs.jar;D:\path\jdk\jdk8\jdk\jre\lib\javaws.jar;D:\path\jdk\jdk8\jdk\jre\lib\jce.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfr.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfxswt.jar;D:\path\jdk\jdk8\jdk\jre\lib\jsse.jar;D:\path\jdk\jdk8\jdk\jre\lib\management-agent.jar;D:\path\jdk\jdk8\jdk\jre\lib\plugin.jar;D:\path\jdk\jdk8\jdk\jre\lib\resources.jar;D:\path\jdk\jdk8\jdk\jre\lib\rt.jar;D:\data\mayikt-designmode\mayikt-single\target\classes;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-web\2.2.3.RELEASE\spring-boot-starter-web-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter\2.2.3.RELEASE\spring-boot-starter-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot\2.2.3.RELEASE\spring-boot-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-autoconfigure\2.2.3.RELEASE\spring-boot-autoconfigure-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-logging\2.2.3.RELEASE\spring-boot-starter-logging-2.2.3.RELEASE.jar;D:\maven\mvnRespo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\mvnRespo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\mvnRespo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\mvnRespo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\mvnRespo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\mvnRespo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-json\2.2.3.RELEASE\spring-boot-starter-json-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-tomcat\2.2.3.RELEASE\spring-boot-starter-tomcat-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-validation\2.2.3.RELEASE\spring-boot-starter-validation-2.2.3.RELEASE.jar;D:\maven\mvnRespo\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\maven\mvnRespo\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\maven\mvnRespo\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\maven\mvnRespo\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\maven\mvnRespo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;D:\maven\mvnRespo\com\alibaba\fastjson\1.2.73\fastjson-1.2.73.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-starter\1.1.1\mybatis-spring-boot-starter-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\1.1.1\mybatis-spring-boot-autoconfigure-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\mybatis\3.4.0\mybatis-3.4.0.jar;D:\maven\mvnRespo\org\mybatis\mybatis-spring\1.3.0\mybatis-spring-1.3.0.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-jdbc\2.2.3.RELEASE\spring-boot-starter-jdbc-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\zaxxer\HikariCP\3.4.2\HikariCP-3.4.2.jar;D:\maven\mvnRespo\org\springframework\spring-jdbc\5.2.3.RELEASE\spring-jdbc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-tx\5.2.3.RELEASE\spring-tx-5.2.3.RELEASE.jar;D:\maven\mvnRespo\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;D:\maven\mvnRespo\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\idea-mayikt\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar" com.mayikt.test.Test04
Connected to the target VM, address: '127.0.0.1:56436', transport: 'socket'
true
Exception in thread "main" java.lang.InstantiationException: com.mayikt.singleton.Singleton03
	at java.lang.Class.newInstance(Class.java:427)
	at com.mayikt.test.Test04.main(Test04.java:22)
Caused by: java.lang.NoSuchMethodException: com.mayikt.singleton.Singleton03.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.newInstance(Class.java:412)
	... 1 more

在根据该返回可以发现是有参构造函数第一个参数为String类型 第二参数为int类型

img

使用有参构造函数 调用 继续报错

        Singleton03 instance1 = Singleton03.INSTANCE;
        Class<?> aClass = Class.forName("com.mayikt.singleton.Singleton03");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
        declaredConstructor.setAccessible(true);
        Singleton03 singleton03 = (Singleton03) declaredConstructor.newInstance("1", 0);
        Singleton03 instance3 = (Singleton03) aClass.newInstance();
        System.out.println(instance3 == instance1);
---------------------------------------------------------
    D:\path\jdk\jdk8\jdk\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:61979,suspend=y,server=n -javaagent:C:\Users\mayikt\AppData\Local\JetBrains\IntelliJIdea2020.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\path\jdk\jdk8\jdk\jre\lib\charsets.jar;D:\path\jdk\jdk8\jdk\jre\lib\deploy.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\access-bridge-64.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\cldrdata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\dnsns.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jaccess.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jfxrt.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\localedata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\nashorn.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunec.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunjce_provider.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunmscapi.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunpkcs11.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\zipfs.jar;D:\path\jdk\jdk8\jdk\jre\lib\javaws.jar;D:\path\jdk\jdk8\jdk\jre\lib\jce.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfr.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfxswt.jar;D:\path\jdk\jdk8\jdk\jre\lib\jsse.jar;D:\path\jdk\jdk8\jdk\jre\lib\management-agent.jar;D:\path\jdk\jdk8\jdk\jre\lib\plugin.jar;D:\path\jdk\jdk8\jdk\jre\lib\resources.jar;D:\path\jdk\jdk8\jdk\jre\lib\rt.jar;D:\data\mayikt-designmode\mayikt-single\target\classes;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-web\2.2.3.RELEASE\spring-boot-starter-web-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter\2.2.3.RELEASE\spring-boot-starter-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot\2.2.3.RELEASE\spring-boot-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-autoconfigure\2.2.3.RELEASE\spring-boot-autoconfigure-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-logging\2.2.3.RELEASE\spring-boot-starter-logging-2.2.3.RELEASE.jar;D:\maven\mvnRespo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\mvnRespo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\mvnRespo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\mvnRespo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\mvnRespo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\mvnRespo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-json\2.2.3.RELEASE\spring-boot-starter-json-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-tomcat\2.2.3.RELEASE\spring-boot-starter-tomcat-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-validation\2.2.3.RELEASE\spring-boot-starter-validation-2.2.3.RELEASE.jar;D:\maven\mvnRespo\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\maven\mvnRespo\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\maven\mvnRespo\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\maven\mvnRespo\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\maven\mvnRespo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;D:\maven\mvnRespo\com\alibaba\fastjson\1.2.73\fastjson-1.2.73.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-starter\1.1.1\mybatis-spring-boot-starter-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\1.1.1\mybatis-spring-boot-autoconfigure-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\mybatis\3.4.0\mybatis-3.4.0.jar;D:\maven\mvnRespo\org\mybatis\mybatis-spring\1.3.0\mybatis-spring-1.3.0.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-jdbc\2.2.3.RELEASE\spring-boot-starter-jdbc-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\zaxxer\HikariCP\3.4.2\HikariCP-3.4.2.jar;D:\maven\mvnRespo\org\springframework\spring-jdbc\5.2.3.RELEASE\spring-jdbc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-tx\5.2.3.RELEASE\spring-tx-5.2.3.RELEASE.jar;D:\maven\mvnRespo\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;D:\maven\mvnRespo\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\idea-mayikt\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar" com.mayikt.test.Test04
Connected to the target VM, address: '127.0.0.1:61979', transport: 'socket'
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at com.mayikt.test.Test04.main(Test04.java:27)
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at com.mayikt.thread.days15.Test01.main(Test01.java:23)

枚举不能够被反射 ,反射底层代码有判断处理

img

序列化攻击枚举

package com.mayikt.test;

import com.mayikt.singleton.Singleton03;

import java.io.*;

/**
 * @author 余胜军
 * @ClassName Test05
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public class Test05 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Singleton03 instance = Singleton03.INSTANCE;
        FileOutputStream fos = new FileOutputStream("D:\\mayikt/a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Singleton03 singleton3 = Singleton03.INSTANCE;
        oos.writeObject(singleton3);
        oos.close();
        fos.close();
        System.out.println("----------从硬盘中反序列化对象到内存中------------");
        //2.从硬盘中反序列化对象到内存中
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\mayikt/a.txt"));
        // 从新获取一个新的对象
        Singleton03 singleton4 = (Singleton03) ois.readObject();
        System.out.println(instance == singleton4);
    }
}

Enum.valueOf((Class)cl, name),这样实现的现过其实就是EnumClass.name(我代码的体现是Singleton.INSTANCE),这样来看的话无论是EnumClass.name获取对象,还是Enum.valueOf((Class)cl, name)获取对象,它们得到的都是同一个对象,这其实就是枚举保持单例的原理

public enum Color {
    RED("a",0),
    GREEN("b",1),
    BLUE("c",2);
    private final String name;
    private final Integer value;
    Color(String name, Integer value) {
        this.name = name;
        this.value = value;
    }
    public String getName() {
        return this.name;
    }
    public Integer getValue() {
        return this.value;
    }
}


        Color a = Color.valueOf("RED");
        System.out.println(a.getName());
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   Color.java

package com.mayikt.test;


public final class Color extends Enum
{

	public static final Color RED;
	public static final Color GREEN;
	public static final Color BLUE;
	private final String name;
	private final Integer value;
	private static final Color $VALUES[];

	public static Color[] values()
	{
		return (Color[])$VALUES.clone();
	}

	public static Color valueOf(String name)
	{
		return (Color)Enum.valueOf(com/mayikt/test/Color, name);
	}

	private Color(String s, int i, String name, Integer value)
	{
		super(s, i);
		this.name = name;
		this.value = value;
	}

	public String getName()
	{
		return name;
	}

	public Integer getValue()
	{
		return value;
	}

	static 
	{
		RED = new Color("RED", 0, "a", Integer.valueOf(0));
		GREEN = new Color("GREEN", 1, "b", Integer.valueOf(1));
		BLUE = new Color("BLUE", 2, "c", Integer.valueOf(2));
		$VALUES = (new Color[] {
			RED, GREEN, BLUE
		});
	}
}

代码下载:

📎设计模式课程.rar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值