枚举类型为什么能实现单例模式?

枚举是固定的常量集合,具有final性质,不允许客户端创建额外实例。Java枚举本质是int值,其构造方法默认私有,确保外部无法通过new操作创建实例。这使得枚举天然适合实现单例模式,类似于饿汉式的单例,枚举会自动为每个枚举常量创建唯一实例,保证了全局只有一个实例存在。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义:
枚举是指一组固定常量组成合法值的类型

首先是固定常量,一组有限常量集,比如一年的四个季节,太阳系的行星。其次,枚举是一种特殊的类型,定义了自己的一些规则,这些规则是建立在类规则之上的,是一种 type。

性质:
枚举是真正的 final,客户端不允许创建枚举类的实例,也不能对其进行拓展

Java 枚举本质上是 int 值。只能通过公有的静态 final 域为枚举类导出实例。

public enum Color {
    GREEN,RED,BLUE,GRAY;
}
实际上枚举的完整的结构为:

public enum Color {
    GREEN,RED,BLUE,GRAY;
    Color() {
    }
如果在 Color() 构造方法之前加上 private 则不会有任何问题。如果加上 public 等修饰符,IDE 会报错,也就是编译器不会通过。其实这是枚举与类的根本区别,就在于构造方法私有。

当然如果仅仅是构造方法私有,不再提供构造方法了,也就是说外界不能 new 实例,如果仅从这样看,那枚举就没有什么用了。 
其实我们用过枚举的都知道,GREEN、RED 都是 Color 型的实例,其实枚举也可以看作自动处理了一些东西,帮助简化了代码,翻译成类大致就是:【与单例模式的饿汉式代码一样!!】

public class Color {

    public static final Color GREEN = new Color(),
            RED = new Color(),
            BLUE = new Color(),
            GRAY = new Color();

    private Color() {
    }
}
如果从这种角度去看,枚举的用法就不难理解了,也就是枚举类不给外界实例化的机会,只能它自己实例化,而一个枚举类的所有实例就只有枚举前面分号前的那几个,其他地方不允许创建。
原文:https://blog.youkuaiyun.com/lishuangling21/article/details/71398925 

实践可见:《effective java 》第3条--枚举类型实现单例模式

### Java 单例模式的概念 Java 中的单例模式是一种常见的设计模式,主要目的是确保整个应用程序运行期间某个类仅有一个实存在。通过控制类的实化过程,开发者能够有效管理全局状态并减少不必要的资源消耗[^1]。 #### 单例模式的特点 - **唯一性**:在整个应用生命周期中,某类始终只有一个实。 - **全局访问点**:提供了统一的方式获取唯一的实。 - **延迟加载**:通常情况下,在第一次使用时才初始化实,从而优化性能[^3]。 --- ### Java 单例模式实现方式 以下是几种典型的单例模式实现方式: #### 1. 饿汉式(Eager Initialization) 饿汉式是在类加载阶段就完成实化的实现方式。由于静态变量 `instance` 被声明为 `final` 和 `static`,因此 JVM 可以保证线程安全性和唯一性。 ```java public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 这种方式简高效,但由于实在类加载时就被创建,可能浪费资源[^2]。 --- #### 2. 懒汉式(Lazy Initialization) 懒汉式的实现会在调用 `getInstance()` 方法时首次创建实。为了防止多线程环境下的并发问题,需加入同步机制。 ```java public class Singleton { private static Singleton instance; private Singleton() {} public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 虽然解决了延迟加载的问题,但每次调用都需要加锁,影响效率[^4]。 --- #### 3. 双重校验锁定(Double Checked Locking) 双重校验锁定是对懒汉式的改进版本,它减少了不必要的同步操作,提高了性能。 ```java public class Singleton { private volatile static Singleton instance; // 使用volatile关键字确保可见性 private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // 实化对象 } } } return instance; } } ``` 此方法既实现了延迟加载,又能保证线程安全性[^5]。 --- #### 4. 枚举实现(Enum Singleton) 枚举类型单例模式被认为是最简洁和最安全的一种实现方式,天然支持序列化和反序列化保护。 ```java public enum Singleton { INSTANCE; public void doSomething() { System.out.println("Doing something..."); } } ``` 这种实现方式不仅避免了反射攻击的风险,还简化了代码结构。 --- #### 5. 静态内部类(Static Inner Class) 利用静态内部类的特性来实现单例模式,只有当外部类的 `getInstance()` 方法被调用时才会触发内部类的加载。 ```java public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } ``` 这种方法兼具延迟加载的优势,同时无需显式地处理线程安全问题。 --- ### 单例模式的优点与缺点 #### 优点 - 减少内存占用,节约系统资源。 - 提高性能,尤其适用于频繁创建销毁的对象。 - 统一对外接口,便于管理和维护。 #### 缺点 - 违背一职责原则,增加耦合度。 - 不适合需要动态扩展的应用场景。 - 对于其他开发人员来说不够直观,容易引起误解。 --- ### § 1. 如何判断一个类是否适合作为? 2. 在分布式环境中如何实现跨进程的单例模式? 3. 如果类需要支持序列化功能,应该注意哪些细节? 4. 哪些实际应用场景最适合采用单例模式? 5. 反射机制是否会破坏单例模式的安全性?如果会,该如何解决?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值