- 使用枚举内部类的单例
- 尝试直接通过枚举反射创建实例
- 反编译查看枚举单例模式源码(证明其是饿汉模式)
如下的类, 使用枚举的内部类方式创建单例. 在枚举中的构造方法创建对象 .
public class EnumStaringSingleton {
// 私有无参构造函数
private EnumStaringSingleton() {
}
public static EnumStaringSingleton getInstance() {
return ContainerHolder.HOLDER.instance;
}
private enum ContainerHolder {
// 保存单例对象
HOLDER;
private EnumStaringSingleton instance;
// 枚举的构造方法, 加载的时候就创建出对象, 饿汉式写法
ContainerHolder() {
instance = new EnumStaringSingleton();
}
}
}
测试 编写如下的测试, 分别通过类名调用静态方法, 和通过反射来创建对象.
@Test
public void EnumStaringSingletonTest() throws Exception {
// 通过调用静态方法创建对象
System.out.println(EnumStaringSingleton.getInstance());
// 通过反射创建对象
Class clazz = EnumStaringSingleton.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
EnumStaringSingleton singleton = constructor.newInstance();
System.out.println(singleton.getInstance());
}
结果如下, 可以看到是两个一样的对象.
在EnumStaringSingleton类中, 写如下的main方法, 该方法内直接通过获取枚举的class对象, 来创建实例.
public static void main(String[] args) throws Exception{
Class clazz = ContainerHolder.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
System.out.println(EnumStaringSingleton.getInstance());
System.out.println(constructor.newInstance());
}
运行后 , 报异常如下 java.lang.NoSuchMethodException
原因是枚举中, 没有无参构造函数, 只有一个带参数的构造函数, String . int
将代码改成如下的, 带参数的
运行后依旧报错,
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
, 说明了不能通过 反射的形式, 创建枚举的对象. 说明了枚举是无法通过反射的方式去破解的
jad 来反编译. 下载网址 https://varaneckas.com/jad/ 根据不同的操作系统进行下载. 我是windows ,因此下载第一个.虽然上面标着是要在intel平台上, 但是 我的CPU是AMD也能用. 下载完成后 ,解压, 可以看到jad.exe
要反编译EnumStaringSingleton文件, 那么首先要生成.class文件. 使用javac命令进行生成. 执行如下的名称, 前面为文件的路径.
D:\mycode\spring_study\simpleframework\src\main\java\demo\pattern>javac EnumStaringSingleton.java
执行编译的时候有报错, 错误: 编码 GBK 的不可映射字符 (0xB0)
, 比较快的解决方式是去除中文注释.
再用jad进行反编译如下: 先传入jad.exe的路径, 再传入class文件的路径.
D:\mycode\spring_study\simpleframework\src\main\java\demo\pattern>D:\softpack\jad158g.win\jad.exe EnumStaringSingleton.class
Parsing EnumStaringSingleton.class...Parsing inner class EnumStaringSingleton$ContainerHolder.class... Generating EnumStaringSingleton.jad
会生成一个如下的jad文件 内容如下
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumStaringSingleton.java
package demo.pattern;
public class EnumStaringSingleton
{
private static final class ContainerHolder extends Enum
{
public static ContainerHolder[] values()
{
return (ContainerHolder[])$VALUES.clone();
}
public static ContainerHolder valueOf(String s)
{
return (ContainerHolder)Enum.valueOf(demo/pattern/EnumStaringSingleton$ContainerHolder, s);
}
public static final ContainerHolder HOLDER;
private EnumStaringSingleton instance;
private static final ContainerHolder $VALUES[];
static
{
HOLDER = new ContainerHolder("HOLDER", 0);
$VALUES = (new ContainerHolder[] {
HOLDER
});
}
private ContainerHolder(String s, int i)
{
super(s, i);
instance = new EnumStaringSingleton();
}
}
private EnumStaringSingleton()
{
}
public static EnumStaringSingleton getInstance()
{
return ContainerHolder.HOLDER.instance;
}
}
通过上面的内容可以看到 , 枚举ContainerHolder, 反编译后, 本质是一个静态类, 去继承了枚举 private static final class ContainerHolder extends Enum
创建单例对象是如下的静态代码块 . 说明了枚举的单例是饿汉模式.
static
{
HOLDER = new ContainerHolder("HOLDER", 0);
$VALUES = (new ContainerHolder[] {
HOLDER
});
}
破解单例模式还有序列化与反序列的方式, 在反序列的时候, 再创建一个单例.