记录一下无聊的我
1 枚举模式实现单例模式
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
好的,来测试一下
class Client{
public static void main(String[] args) throws Exception {
EnumSingle s1 = EnumSingle.INSTANCE;
EnumSingle s2 = EnumSingle.INSTANCE;
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
结果没有问题,拿到的是同一个。
2 想办法破解一下
2.1序列化和反序列化破坏
class Client{
public static void main(String[] args) throws Exception {
writeObject2File();
EnumSingle s1 = readObjectFromFile();
EnumSingle s2 = readObjectFromFile();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
private static EnumSingle readObjectFromFile() throws Exception {
//创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
//第一个读取EnumSingle对象
EnumSingle instance = (EnumSingle) ois.readObject();
return instance;
}
public static void writeObject2File() throws Exception {
//获取EnumSingle类的对象
EnumSingle instance = EnumSingle.INSTANCE;
//创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
//将EnumSingle对象写出到文件中
oos.writeObject(instance);
}
}
结果如下,很好,没有被破坏。
2.2 通过反射
class Client{
public static void main(String[] args) throws Exception {
Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor();
constructor.setAccessible(true);
EnumSingle s1 = constructor.newInstance();
EnumSingle s2 = constructor.newInstance();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
结果报错,,没有构造方法。
于是反编译看一下。
发现其实是有参构造。那就把获取构造器的代码改一下
Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
再次尝试,结果如下:不能反射地创建enum对象。
这就只能点到源码看一下了。
可以看到,java它自己就不允许对枚举进行反射。所以说枚举是安全的单例。
3 一个无聊的人
其实到这里,写的虽然不咋地,但是也没有出现奇怪的操作。然后,,,,我就想,要不我把这行代码注释掉,看看是啥样吧。
于是
找到了Constructor 这个类的位置。在jre/lib/ 下rt.jar 包 java\lang\reflect\ 下面。
先把这个 jar 包备份一下。
复制一份源码,把这两行给注释掉
@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();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
然后编译一下,把产生的class 文件替换一下。
接着,启动自己的idea,再次跑一下刚才的代码。结果如下:
好了,不一样了。
所以,完全没有啥用,还得把包给替换回来。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!