设计模式课程 设计模式精讲 8-8 单例设计模式-Enum枚举单例、原理源码解析以及反编译实战
1 课堂解析
2 代码演练
2.1 枚举类单例解决序列化破坏demo
2.2 枚举类单例解决序列化破坏原理
2.3 枚举类单例解决反射攻击demo
2.4 枚举类单例解决反射攻击原理
3 jad的使用
3.1 网址:
1 课堂解析
2 代码演练
2.1 枚举类单例解决序列化破坏demo
枚举类:
package com.geely.design.pattern.creational.singleton; /**
* 这个类是enum类型
*/
public enum EnumInstance {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量。
* 因此在某些时候为了节省系统内存开销、共享资源,可以将类中的一些变量声明为静态变量!
*
* 最最主要的原因,单例模式外部类不能new出对象,要使用该方法只能是静态的
*
* 最终返回的肯定是本类,所以该方法的类型为EnumInstance
*/
public static EnumInstance getInstane(){
return INSTANCE;
} }
测试类:
package com.geely.design.pattern.creational.singleton; import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; public class Test {
/**
* 序列化代码演练
* 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
* 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
*
* @param args
*/
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
try {
//将singleton对象写入到输出流中
EnumInstance instance = EnumInstance.getInstane();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance); //从输入流中读取到该对象
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance instance2 = (EnumInstance) ois.readObject();
System.out.println(instance);
System.out.println(instance2);
System.out.println(instance == instance2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
}
打印日志:
"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=42967: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.singleton.Test
INSTANCE
INSTANCE
true Process finished with exit code 0
2.2 枚举类单例解决序列化破坏原理
ObjectInputStream
/**
* Underlying readObject implementation.
*/
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
} byte tc;
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
} depth++;
try {
switch (tc) {
case TC_NULL:
return readNull(); case TC_REFERENCE:
return readHandle(unshared); case TC_CLASS:
return readClass(unshared); case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared); case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared)); case TC_ARRAY:
return checkResolve(readArray(unshared));
/*
* 注意:读取enum
*
*/
case TC_ENUM:
return checkResolve(readEnum(unshared)); case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex); case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
} case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
} default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
} /**
* Reads in and returns enum constant, or null if enum type is
* unresolvable. Sets passHandle to enum constant's assigned handle.
*/
private Enum readEnum(boolean unshared) throws IOException {
if (bin.readByte() != TC_ENUM) {
throw new InternalError();
} ObjectStreamClass desc = readClassDesc(false);
if (!desc.isEnum()) {
throw new InvalidClassException("non-enum class: " + desc);
} int enumHandle = handles.assign(unshared ? unsharedMarker : null);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(enumHandle, resolveEx);
} String name = readString(false);//通过readString方法获取到枚举对象的名称
Enum en = null;
Class cl = desc.forClass();
if (cl != null) {
try {
en = Enum.valueOf(cl, name);//通过类型和名称获取到枚举常量,枚举中的name是唯一的,并且对应一个枚举常量,所以拿到的肯定是唯一的对象。
} catch (IllegalArgumentException ex) {
throw (IOException) new InvalidObjectException(
"enum constant " + name + " does not exist in " +
cl).initCause(ex);
}
if (!unshared) {
handles.setObject(enumHandle, en);
}
} handles.finish(enumHandle);
passHandle = enumHandle;
return en;
}
2.3 枚举类单例解决反射攻击demo
枚举类:(同2.1)
package com.geely.design.pattern.creational.singleton; /**
* 这个类是enum类型
*/
public enum EnumInstance {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量。
* 因此在某些时候为了节省系统内存开销、共享资源,可以将类中的一些变量声明为静态变量!
*
* 最最主要的原因,单例模式外部类不能new出对象,要使用该方法只能是静态的
*
* 最终返回的肯定是本类,所以该方法的类型为EnumInstance
*/
public static EnumInstance getInstane(){
return INSTANCE;
} }
测试类:
package com.geely.design.pattern.creational.singleton; import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; public class Test { /**
* 序列化代码演练
* 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
* 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
*
* @param args
*/
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/*try {
//将singleton对象写入到输出流中
EnumInstance instance = EnumInstance.getInstane();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance); //从输入流中读取到该对象
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance instance2 = (EnumInstance) ois.readObject();
System.out.println(instance);
System.out.println(instance2);
System.out.println(instance == instance2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}*/ Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor();
constructor.setAccessible(true);
}
}
打印结果:
"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=43086: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.singleton.Test
Exception in thread "main" java.lang.NoSuchMethodException: com.geely.design.pattern.creational.singleton.EnumInstance.<init>()
at java.lang.Class.getConstructor0(Class.java:2892)
at java.lang.Class.getDeclaredConstructor(Class.java:2058)
at com.geely.design.pattern.creational.singleton.Test.main(Test.java:148) Process finished with exit code 1
反射有参对象:
package com.geely.design.pattern.creational.singleton; import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; public class Test {
/**
* 序列化代码演练
* 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
* 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
*
* @param args
*/
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/*try {
//将singleton对象写入到输出流中
EnumInstance instance = EnumInstance.getInstane();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance); //从输入流中读取到该对象
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance instance2 = (EnumInstance) ois.readObject();
System.out.println(instance);
System.out.println(instance2);
System.out.println(instance == instance2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}*/ Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumInstance enumInstance = (EnumInstance) constructor.newInstance("dd",123); }
}
打印结果:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:521)
at com.geely.design.pattern.creational.singleton.Test.main(Test.java:150) Process finished with exit code 1
2.4 枚举类单例解决反射攻击原理
Enum.java
只有有参构造器
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
Constructor.java
/**
* Uses the constructor represented by this {@code Constructor} object to
* create and initialize a new instance of the constructor's
* declaring class, with the specified initialization parameters.
* Individual parameters are automatically unwrapped to match
* primitive formal parameters, and both primitive and reference
* parameters are subject to method invocation conversions as necessary.
*
* <p>If the number of formal parameters required by the underlying constructor
* is 0, the supplied {@code initargs} array may be of length 0 or null.
*
* <p>If the constructor's declaring class is an inner class in a
* non-static context, the first argument to the constructor needs
* to be the enclosing instance; see section 15.9.3 of
* <cite>The Java™ Language Specification</cite>.
*
* <p>If the required access and argument checks succeed and the
* instantiation will proceed, the constructor's declaring class
* is initialized if it has not already been initialized.
*
* <p>If the constructor completes normally, returns the newly
* created and initialized instance.
*
* @param initargs array of objects to be passed as arguments to
* the constructor call; values of primitive types are wrapped in
* a wrapper object of the appropriate type (e.g. a {@code float}
* in a {@link java.lang.Float Float})
*
* @return a new object created by calling the constructor
* this object represents
*
* @exception IllegalAccessException if this {@code Constructor} object
* is enforcing Java language access control and the underlying
* constructor is inaccessible.
* @exception IllegalArgumentException if the number of actual
* and formal parameters differ; if an unwrapping
* conversion for primitive arguments fails; or if,
* after possible unwrapping, a parameter value
* cannot be converted to the corresponding formal
* parameter type by a method invocation conversion; if
* this constructor pertains to an enum type.
* @exception InstantiationException if the class that declares the
* underlying constructor represents an abstract class.
* @exception InvocationTargetException if the underlying constructor
* throws an exception.
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)//如果目标类是枚举类型,抛出异常
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
return (T) ca.newInstance(initargs);
3 jad的使用
3.1 网址:
https://varaneckas.com/jad/
设计模式课程 设计模式精讲 8-8 单例设计模式-Enum枚举单例、原理源码解析以及反编译实战的更多相关文章
- 【趣味设计模式系列】之【代理模式3--Cglib动态代理源码解析】
1. 图解 上图主要描述了Cglib动态代理的主要执行过程,下面做详细分析,以下源码使用的Cglib版本为3.2.12. 2. Enhancer源码分析 public Object create() ...
- 【趣味设计模式系列】之【代理模式2--JDK动态代理源码解析】
1. 图解 上图主要描述了JDK动态代理的执行过程,下面做详细分析. 2. Proxy源码分析 上一篇,在使用JDK动态代理的时候,借助于Proxy类,使用newProxyInstance静态方法,创 ...
- 【设计模式】Java设计模式精讲之原型模式
简单记录 - 慕课网 Java设计模式精讲 Debug方式+内存分析 & 设计模式之禅-秦小波 文章目录 1.原型模式的定义 原型-定义 原型-类型 2.原型模式的实现 原型模式的通用类图 原 ...
- 设计模式课程 设计模式精讲 7-2 建造者模式Coding
1 代码演练 1.1 建造者模式演练 1.2 静态内部类演练建造者模式(链式调用) 1 代码演练 1.1 建造者模式演练 需求: 根据讲师提供的课程名称,课程ppt,课程视频,课程手记,课程问答 制作 ...
- 设计模式课程 设计模式精讲 17-2 模板方法模式coding
1 代码演练 1.1 代码演练1 1.2 代码演练2(后端课程子类运用钩子方法,加入写手记的方法) 1.3 代码演练3(前端有多个子类,有得需要写手记,有得不需要写,如何实现?) 1 代码演练 1.1 ...
- 设计模式课程 设计模式精讲 8-11 单例模式源码解析(jdk+spring+mybaties)
1 源码解析 1.1 单例解析1 1.2 单例解析2(容器单例) 1.3 单例解析3 1.4 单例解析4 1 源码解析 1.1 单例解析1 java.lang.Runtime /** * 饿汉式加载, ...
- Java设计模式精讲之UML急速入门
简单记录 - 慕课网 - Java设计模式精讲 Debug方式+内存分析 文章目录 第2章 UML急速入门 2-1.UML简单入门 UML定义 UML特点 UML 2.2分类 UML类图 理解泛化.实 ...
- iOS开发之单例设计模式(完整正确版本)
单例的意思从字面上就可以略知一二,所谓单例就是确保在程序运行过程中只创建一个对象实例.可以用于需要被多次广泛或者说多次使用的资源中,比如我们常见的网络请求类.工具类以及其它管理类等.比如我iOS开发中 ...
- JAVA_SE基础——38.单例设计模式
本文继续介绍23种设计模式系列之单例模式. 我们在javaSE的基础学习中,会讲到:单例设计模式.模板设计模式.装饰者设计模式.观察者设计模式.工厂设计模式 我以后随着水平的提高,我会专门开个分类写设 ...
随机推荐
- ACM进阶之路
第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码, 因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打 出来. 3.大数(高精度)加减乘除 ...
- 架设传奇时打开DBC数据库出错或读取DBC失败解决方法
架设传奇时打开DBC数据库出错或读取DBC失败解决方法 DBC右键-属性-高级-管理员身份运行 即可
- P3378 (模板)并查集
使用带路径压缩的并查集,不然会TLE AC代码: #include <bits/stdc++.h> #define MP make_pair #define PB push_back #d ...
- Python - 关于属性访问的优先级,属性访问顺序,python attributel lookup,类和实例访问属性的顺序
object.__getattribute__(self, name) 类中的数据描述符 object.__dict__.get(name) 自身属性字典 object.__class__.__dic ...
- selenium 元素查找与属性
1.首先你要安装selenium库啦 pip install selenium 2.selenium查找元素就八种方法 from selenium import webdriver driver=we ...
- SpringBoot RESTful API 架构风格实践
如果你要问 Spring Boot 做什么最厉害,我想答案就在本章标题 RESTful API 简称 REST API . 本项目源码下载 1 RESTful API 概述 1.1 什么是 RESTf ...
- webpack搭建vue项目
链接:https://blog.csdn.net/qq_42181069/article/details/81137180 __dirname : 文件的绝对路径
- formValidation单个输入框值改变时校验
$("#tv_form").data("formValidation").updateStatus("pay.vcAmount", &qu ...
- [总结]一些 DP 优化方法
目录 注意本文未完结 写在前面 矩阵快速幂优化 前缀和优化 two-pointer 优化 决策单调性对一类 1D/1D DP 的优化 \(w(i,j)\) 只含 \(i\) 和 \(j\) 的项--单 ...
- ArrayStack(栈)
顺序栈即数组型的栈.什么是栈呢?简单来说就像一个刚好装的下乒乓球大小的球筒,假设不能暴力打开球筒且只有一端有出口,那你放入或取出里面的球的操作都只能在一端进行,并且把球放进去或取出来都是由顺序决定的, ...