当前位置: 首页 > wzjs >正文

订做网站建设站长工具一区

订做网站建设,站长工具一区,动态图网站怎么做dw,网页设计图片欣赏前言: 我们知道实现单例模式的方式有三种,分别是:双重锁,静态内部类,枚举类 其中枚举类是最优雅,最安全的实现方式 相信绝大多数人最开始学的单例模式的实现就是双重锁的实现,这种方式虽然保证的线程安全和懒加载,但是仍然存在两个问题,会导致单例模式被破坏 通过反射可以获取到…

前言:
我们知道实现单例模式的方式有三种,分别是:双重锁,静态内部类,枚举类
其中枚举类是最优雅,最安全的实现方式
相信绝大多数人最开始学的单例模式的实现就是双重锁的实现,这种方式虽然保证的线程安全和懒加载,但是仍然存在两个问题,会导致单例模式被破坏

  1. 通过反射可以获取到类的相关信息,访问到类的私有构造方法,再次创建一个实例对象,破坏单例模式
  2. 先序列化,再反序列化:每一次反序列化(字节流转换为Java对象)都会创建一个新的Java对象,也会破坏单例模式

枚举类可以很好的解决上述两种问题,原因如下:

  1. 枚举类无法通过反射获取私有方法,如果尝试获取就会抛出异常
  2. 枚举类实现了serilizable接口,反序列化创建的java对象始终唯一

以下是原理讲解


🧱 一、你需要知道的基本概念

🔑 1. 什么是反射攻击?

Java 的反射(Reflection)机制允许你在运行时访问类的私有构造方法,这就可能绕过单例模式的限制,创建多个实例。

👉 举例说明:

Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton newInstance = constructor.newInstance();  // 又创建了一个新对象

🔑 2. 什么是序列化攻击?

当你对一个对象序列化后再反序列化,如果没有处理好 readResolve() 方法,可能会重新创建一个新的实例。

👉 举例说明:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.ser"));
oos.writeObject(singleton);  // 序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.ser"));
Singleton newInstance = (Singleton) ois.readObject();  // 又是一个新对象

🚧 二、普通单例是如何被破坏的?

我们先看看一个普通单例是如何被攻击的:

🚫 普通单例类:

public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

🔨 利用反射:

Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton another = constructor.newInstance();  // 💥 新的对象!

即使你用了 private 构造函数,反射还是可以绕过访问控制


✅ 三、枚举类如何防反射攻击?

🧠 枚举的底层原理(JVM限制)

枚举的构造方法会被编译器标记为 private,并且由 JVM 明确规定:

不能通过反射来创建枚举类的实例。

👉 举个例子:

public enum SingletonEnum {INSTANCE;
}

🔍 用反射尝试攻击:

Constructor<SingletonEnum> constructor = SingletonEnum.class.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
SingletonEnum instance = constructor.newInstance("INSTANCE", 0);

🔥 运行时会抛出异常:

java.lang.IllegalArgumentException: Cannot reflectively create enum objects

✅ 原因:

JVM 源码中明确做了限制(在 Reflect.newInstance()ConstructorAccessorImpl.newInstance()):

if (clazz.isEnum()) {throw new IllegalArgumentException("Cannot reflectively create enum objects");
}

🚫 所以:枚举类实例无法通过反射创建,天然防御反射攻击。


✅ 四、枚举类如何防序列化攻击?

🔁 普通类的反序列化攻击原理

如果一个单例类实现了 Serializable,默认情况下每次反序列化都会创建新对象,除非你手动实现 readResolve() 方法。

🔍 漏洞示意:

public class Singleton implements Serializable {private static final Singleton instance = new Singleton();public static Singleton getInstance() { return instance; }
}

即使是单例,序列化再反序列化后:

Singleton s1 = Singleton.getInstance();
Singleton s2 = deserialize("singleton.obj");
System.out.println(s1 == s2);  // false ❌

🧠 而枚举类型在反序列化时自动保证单例!

public enum SingletonEnum {INSTANCE;
}

⚙ 枚举类自动实现了 Serializable,并且 JVM 源码中会调用:

return Enum.valueOf(enumType, name); // 返回同一个实例

即便你什么都不写,枚举的反序列化机制会自动返回枚举常量 INSTANCE始终是同一个对象


📘 来自《Effective Java》的权威背书

在《Effective Java》第三版第3条中,作者 Joshua Bloch 写道:

“枚举类型是实现单例的最佳方式。它简洁、自动支持序列化机制,并提供了对抗多重实例化攻击的绝对保障,即使面对复杂的反射和序列化攻击。”


✅ 总结:枚举单例的天然安全性

安全防护项普通单例需要额外处理枚举单例
线程安全❌(需加锁或静态内部类)✅ JVM 保证
反射攻击❌(可被破坏)✅ JVM 禁止
序列化攻击❌(需要重写 readResolve()✅ JVM 自动处理
写法简洁✅✅✅

🏁 如果你记住一句话:

枚举单例,是唯一能在 语言层面 自动防止反射 + 反序列化攻击的实现方式,也是 Java 实现单例模式的终极形态。


http://www.dtcms.com/wzjs/17366.html

相关文章:

  • 设计做网站网站推广的案例
  • 百度站长工具大全seo关键词排名优化方案
  • 苏州网站建设网络推广百度网站链接
  • 先做网站后备案吗网站前期推广
  • 合肥市做网站多少钱滨州seo招聘
  • 建设网站有什么法律么运营推广的方式和渠道有哪些
  • 网站建设服务费属于什么科目搜索引擎营销优化
  • 上海做网站收费免费制作网站app
  • 安徽省建设安全监督站的网站兰州网络推广公司哪家好
  • 上海网站优化推广济南seo外包公司
  • 企业网站建设电话互联网广告代理可靠吗
  • 营销型网站设计价格网络推广项目
  • 代理公司招标流程网站seo
  • 镇江网站定制宁波 seo整体优化
  • wordpress资源消耗湖南专业seo推广
  • wordpress前端上传图片优化设计方法
  • 做游戏还是做网站好网站优化的意义
  • 如何做网站浏览pdf福州seo按天收费
  • 做网站的公司怎么找外包推广服务
  • 劳务公司找项目平台seo网络排名优化哪家好
  • 深圳制作公司网站的公司怎么自己制作网页
  • 二级域名著名网站window优化大师
  • 网站建设网站建设的网络公司快速排序优化
  • 做网站的语网站怎么做到秒收录
  • 营销网站建设推广东莞seo排名优化
  • 哪里有做独立网站的服务器谷歌seo服务公司
  • 深圳龙华汽车站附近有做网站建设的百度热搜广告设计公司
  • 虎门专业做网站手机如何制作网页
  • 产品设计优秀网站下载安装百度
  • 网站分为哪些部分组成部分组成今天新闻头条