单元素的枚举类型已经成为实现Singleton的最佳方法

本文详细介绍了单例模式的多种实现方式,包括双重检查锁定、饿汉式及其变种、静态内部类等,并对比了这些方法的优缺点。最后介绍了使用枚举实现单例模式的方法,该方法简洁且能有效防止多次实例化。

转载请注明出处
http://blog.youkuaiyun.com/guodongAndroid/article/details/52032750
本文来自【孫小逗的博客】

一、概述

Singleton模式是在编程实践中应用最广泛的几种设计模式之一。以前常用的是下面的这种方法:

public class Singleton
{
    private volatile static Singleton instance;

    private Singleton(){};

    public static Singleton getInstance()
    {
        if (instance == null)
        {
            synchronized (Singleton.class)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

这种方法称为双重校验锁,极不推荐使用。

二、其他实现Singleton的方法

1、饿汉式:
public class Singleton
{
    public static final Singleton INSTANCE = new Singleton();
    private Singleton(){};
}
2、饿汉式变种(1)
public class Singleton
{
    private static final Singleton INSTANCE = new Singleton();
    private Singleton(){};
    public static Singleton getInstance()
    {
        return INSTANCE;
    }
}

这两种方式都要求使用私有构造器,私有构造器仅被调用一次,用来实例化静态final域Singleton.INSTANCE。

3、饿汉式变种(2) 类初始化的时候实例化instance
public class Singleton
{
    private static Singleton instance = null;
    private Singleton(){};
    static
    {
        instance = new Singleton();
    }

    public static Singleton getInstance()
    {
        return instance;
    }
}
4、静态内部类
public class Singleton
{
    private static class SingletonHolder
    {
        private static final Singleton instance = new Singleton();
    }
    private Singleton(){};

    public static Singleton getInstance()
    {
        return SingletonHolder.instance;
    }
}

这四种方法都可以借助AccessibleObject.setAccessible方法,通过反射机制,调用私有构造器创建新的实例,如下图:
这里写图片描述

可见s1 == s2为fasle,说明创建了两个实例,也用失去了Singleton属性。如果需要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。

三、使用单元素的枚举实现Singleton

public enum Singleton
{
    INSTANCE;

    public void dosomething()
    {
        System.out.println(this + " is speaking!");
    }
}

先看下运行后的结果:
这里写图片描述

这里写图片描述

使用单元素的枚举类型实现Singleton时,通过反射机制去创建新的实例时会抛出异常。

和以前的s1 == s2对比,可以看到使用单元素的枚举类型在功能上与公有域方法相近,但是它更加简洁,并且无偿得提供了序列化机制,绝对防止多次实例化。

<think> 首先,用户的问题是:“实现 Singleton方法是声明一个包含元素枚举类型:,细说”。这似乎是打字错误,应该是“实现 Singleton 的一种方法是声明一个包含元素枚举类型:,细说”。意思是详细解释如何使用枚举类型实现例模式。 我的回答需要用中文,因为用户指定了“请使用中文回答问题”。 关键规则: - 回答完问题后,必须提出3-5个 §§相关问题§§。 - §§相关问题§§ 必须输出在回答的末尾。 - 第一行必须是完整输出 "§§相关问题§§"。 - 禁止换行分散,意思是一行输出所有相关问题。 - 示例格式:在回答内容后,直接输出 "§§相关问题§§" 然后列出1. 2. 3. 等。 现在,构建我的回答: 1. **解释枚举例**:详细说明如何在Java中使用枚举来实现例模式。这是Joshua Bloch在Effective Java中推荐的最佳方式。 2. **代码示例**:提供一个Java代码示例来展示实现。 3. **优点**:解释为什么这种方式是好的,比如它是线程安全的、防止序列化和反射攻击等。 4. **结构**:确保回答完整。 然后,在结尾输出 "§§相关问题§§" 并列出3-5个相关问题。相关问题必须基于用户的问题和我的回答。 - 用户问题焦点:枚举例。 - 我的回答焦点:实现细节、优点、潜在问题。 拟定相关问题: 1. 枚举例如何防止反射攻击? 2. 在序列化场景下,枚举例与其他实现方式相比有何优势? 3. 枚举例在Java早期版本中是否有兼容性问题? 4. 如何测试使用枚举例的类? 5. 枚举例是否可以延迟初始化? 确保问题数量在3-5个。 完整回答结构: - 先解释主题。 - 提供代码。 - 讨论优点。 - 然后输出 "§§相关问题§§" followed by the list. 代码示例:使用Java枚举来实现例。 ```java public enum Singleton { INSTANCE; // 例实例 // 可以添加方法 public void doSomething() { System.out.println("Doing something..."); } } ``` 解释: - 枚举类型是隐式final,不能被继承。 - INSTANCE是唯一的实例。 - 线程安全,因为Java保证枚举实例的创建是线程安全的。 - 序列化安全,因为枚举的序列化机制会自动处理。 - 反射攻击无效,因为枚举不能被反射实例化。 最后,输出相关问题。 确保所有内容符合规则:回答完整,相关问题是中文,输出格式正确。 </think> ### 使用枚举类型实现例模式详解 在 Java 中,**通过声明包含元素枚举类型实现例**(Enum Singleton)是《Effective Java》推荐的最佳实践,它天然解决了线程安全、序列化攻击和反射攻击问题。以下是核心解析: #### 1. **代码实现模板** ```java // ▶ 例类声明为枚举类型 public enum Singleton { // ★ 唯一的例实例 INSTANCE; // ★ 添加业务方法 public void doWork() { System.out.println("Singleton is working..."); } } // 调用方式 public class Main { public static void main(String[] args) { Singleton.INSTANCE.doWork(); // ✅ 全局唯一访问点 } } ``` #### 2. **关键机制剖析** - **线程安全** Java 保证枚举实例的初始化是线程安全的(JVM 底层加载机制)。 - **防反射攻击** 枚举的构造器由 JVM 严格控制,反射调用 `Constructor.newInstance()` 会直接抛出 `IllegalArgumentException`。 - **序列化安全** 枚举的序列化仅存储名称(如 `INSTANCE`),反序列化时通过 `Enum.valueOf()` 自动返回原实例,**避免创建新对象**。 - **延迟初始化** 枚举实例在首次访问 `Singleton.INSTANCE` 时加载(静态内部类等效实现)。 #### 3. **与传统方法的对比优势** | 实现方式 | 线程安全 | 防反射 | 防序列化漏洞 | 代码简洁性 | |-------------------|----------|--------|--------------|------------| | 枚举例 | ✅ | ✅ | ✅ | ⭐⭐⭐⭐⭐ | | 双重检查锁定 | ✅ | ❌ | ❌ | ⭐⭐ | | 静态内部类 | ✅ | ❌ | ❌ | ⭐⭐⭐ | | 饿汉式 | ✅ | ❌ | ❌ | ⭐⭐ | #### 4. **典型场景下的缺陷规避** - **继承限制**:枚举类型隐式继承 `java.lang.Enum`,无法再继承其他类 → 通过组合模式解决。 - **内存开销**:枚举类比普通类多约 20% 内存 → 在非极端性能场景可忽略。 - **初始化控制**:无法自定义延迟加载时机 → 改用静态内部类实现(需额外处理序列化)。 #### 5. **反编译验证安全性** 枚举代码编译后等价于: ```java public final class Singleton extends Enum<Singleton> { // JVM 生成私有构造 private Singleton(String name, int ordinal) { super(name, ordinal); } public static final Singleton INSTANCE = new Singleton("INSTANCE", 0); } ``` JVM 禁止外部调用此构造器,确保例绝对唯一。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值