`
1025250620
  • 浏览: 229866 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

枚举类型实现的单例模式(转)

 
阅读更多
我们常用的构造单例模式(Singleton)的方法,一般有2种

1 提供一个静态的公共属性
2 提供一个静态的公共方法

这2个方法,都是采用了私有的构造器来防止外部直接构造实例。 但我们可以用反射的方法,获得多个实例。后面我会给出测试的代码。

从1.5开始,枚举也可以用来获得单例,而且更加可靠。同时又自动提供了一些额外的功能。

先看看测试代码:

import java.lang.reflect.Constructor;  
/** 
* 测试Singleton的可靠性。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
public class TestSingleton {  
  public static void main(String[] args) {  
    testSingleton1();  
    testSingleton2();  
    testSingleton3();  
  }  
  public static void testSingleton1() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton1 s1 = TestSingleton1.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton1");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton1 s2 = (TestSingleton1) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
  public static void testSingleton2() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton2 s1 = TestSingleton2.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton2");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton2 s2 = (TestSingleton2) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
  public static void testSingleton3() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton3 s1 = TestSingleton3.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton3");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton3 s2 = (TestSingleton3) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
}  
/** 
* 一个普通的Singletone实现。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
class TestSingleton1 {  
  private static final TestSingleton1 INSTANCE = new TestSingleton1();  
  public static TestSingleton1 getInstance() {  
    return INSTANCE;  
  }  
  private TestSingleton1() {  
  }  
}  
/** 
* 一个用异常强化了的Singletone实现。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
class TestSingleton2 {  
  private static final TestSingleton2 INSTANCE = new TestSingleton2();  
  public static TestSingleton2 getInstance() {  
    return INSTANCE;  
  }  
  private static boolean initSign;  
  private TestSingleton2() {  
    if (initSign) {  
      throw new RuntimeException("实例只能建造一次");  
    }  
    initSign = true;  
  }  
}  
/** 
* 枚举实现的Singleton 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
enum TestSingleton3 {  
  INSTANCE;  
  public static TestSingleton3 getInstance() {  
    return INSTANCE;  
  }  
}




测试结果
TestSingleton1@c17164/TestSingleton1@1fb8ee3
false
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at TestSingleton.testSingleton2(TestSingleton.java:43)
at TestSingleton.main(TestSingleton.java:11)
Caused by: java.lang.RuntimeException: 实例只能建造一次
at TestSingleton2.<init>(TestSingleton.java:103)
... 6 more
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
at TestSingleton.testSingleton3(TestSingleton.java:61)
at TestSingleton.main(TestSingleton.java:12)


小结:可见,只有第三种枚举的方法才是最安全的。

关于里面提到的,在序列化是可能出现的问题,我看以后在讨论吧。不过因为枚举实现的单例没有这个问题,所以我看以后就用枚举好了,何必自己跟自己过不去呢?
分享到:
评论

相关推荐

    com_枚举方式实现单例模式_代码详解.rar

    为了解决这个问题,Java引入了枚举类型来实现单例模式,这是一种简洁且线程安全的方法。 枚举在Java中是特殊的类,由JVM自动管理,保证了线程安全。当枚举类被加载时,JVM会自动初始化所有的枚举实例,因此在多线程...

    设计模式之单例模式(结合工厂模式)

    静态内部类单例利用Java类加载机制保证了线程安全,而枚举单例则是Java中实现单例的最佳方式,因为它天然支持序列化且防止反射攻击。 在代码实现上,我们可以创建一个名为SingletonFactory的工厂类,其中包含一个...

    单例模式(Singleton)的6种实现

    Java中的枚举类型是线程安全的,并且只会装载一次,设计者充分考虑到了线程安全问题,因此使用枚举实现单例模式是一种简洁而且高效的解决方案。 6. 容器式单例(Singleton Holder) 通过一个私有的静态内部类...

    Java实现单例模式[汇编].pdf

    除了以上三种经典的实现方式,Java 1.5之后引入了枚举类型,也提供了一种更简洁且线程安全的单例实现方式。通过定义一个枚举类,其中包含一个枚举常量,这个枚举常量即为单例实例。这种方式既保证了线程安全,又避免...

    JAVA 枚举单例模式及源码分析的实例详解

    JAVA 枚举单例模式是一种特殊的单例模式实现方式,它使用枚举类型来保证线程安全、防止序列化问题和反射攻击。下面我们将详细解释这个模式的实现原理和源码分析。 线程安全 在 Java 中,枚举类型的实例是在类加载...

    单例模式详解

    5. **枚举单例**:利用枚举类型实现单例模式。 - 优点:简洁高效,线程安全,延迟加载。 - 缺点:使用场景受限。 #### 四、单例模式的复杂性 在实际应用中,单例模式可能还会面临更复杂的情况,例如: 1. **DCL...

    单例模式.ppt

    将单例定义为一个枚举类型,这样不仅能保证线程安全,还能防止反射攻击。枚举是JVM的固有特性,因此它的创建是线程安全的,并且不允许实例化多个枚举实例。 每种实现方式都有其优缺点,选择哪种方式取决于特定的...

    Java单例模式.pdf

    除了上述三种单例模式外,在Java中还可以使用枚举类型来实现单例模式。Java枚举的特性保证了枚举类型的单例性,因为枚举实例是类加载时创建的,且Java虚拟机保证不会创建重复的实例。 单例模式在很多情况下都是很...

    用enum实现单例模式的方法来读取配置文件

    本篇将详细介绍如何利用枚举(enum)来实现单例模式,并结合`Properties`类解析配置文件。 首先,我们来看一下传统的单例模式实现方式,如懒汉式和饿汉式,但这些方法在多线程环境下可能会存在问题。而使用枚举实现...

    单例模式和工厂模式代码

    在Java中,实现单例模式有多种方法,包括懒汉式(线程不安全)、饿汉式(静态常量)、双检锁(DCL)和枚举单例。其中,双检锁和枚举单例是线程安全的,推荐在多线程环境下使用。 ```java // 双检锁/双重校验锁(DCL...

    单例模式 c++

    在C++中实现单例模式有多种方法,下面将详细介绍单例模式的概念、目的以及C++中常见的实现方式。 1. **单例模式的基本概念** - 单例模式是一种创建型设计模式,它限制类的实例化过程,使得一个类只能有一个实例。 ...

    javaweb项目+设计模式(单例模式,工厂模式,动态代理,适配器)

    在Java中实现单例模式有多种方法,包括懒汉式(线程不安全)、饿汉式(线程安全)、双重检查锁定(DCL,线程安全)以及枚举单例。确保单例模式正确实现的关键在于防止多线程环境下的多次实例化和序列化/反序列化时的...

    单例模式案例和笔记,通过案例来了解单例模式

    **枚举实现单例**: 这是Joshua Bloch在《Effective Java》中推荐的方法,枚举的实例化是线程安全的,并且自动防止了反射和序列化攻击。 每种模式都有其适用场景,例如,如果对性能和内存占用非常敏感,可以考虑...

    java-单例模式几种写法

    使用枚举类型实现单例,既简单又线程安全,还能防止序列化破坏单例。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { // ... } } ``` 每种方法都有其优缺点。饿汉式虽然简单...

    java中的单例模式

    此外,Java 5引入的枚举类型提供了一种简洁、线程安全且避免了反射攻击的单例实现方式: ```java public enum Singleton { INSTANCE; } ``` 单例模式虽然简单实用,但也存在一些缺点,如妨碍了继承、不支持多态...

    关于单例模式的知识要点

    5. **枚举类型**:Java枚举是天然的单例模式,既简单又安全。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { } } ``` 然而,单例模式并非总是完美的。它的缺点包括: - **测试...

    单例模式和多例模式

    实现单例模式通常有以下几种方式: 1. 饿汉式(静态常量):在类加载时就完成了初始化,因此没有线程安全问题。 ```java public class Singleton { private static final Singleton INSTANCE = new Singleton(); ...

    单例 模式 singleton

    Java枚举类型天然支持单例模式,既简单又线程安全: ```java public enum SingletonClass { INSTANCE; // 可以添加方法 } ``` 这种方式简洁且易于理解和维护,是推荐的单例实现方式。 总之,单例模式通过限制类...

    设计模式_创建型_单例模式.md

    因此,枚举的写法也是实现单例模式的最佳实践。 ## 单例模式可能遇到的问题 ### 反序列化破坏单例 当单例对象实现java.io.Serializable接口后,即使单例类实现了readResolve()方法,但反序列化过程中仍然会创建一...

    单例模式的七种写法

    将单例定义为枚举类型是一种简洁且线程安全的方式。Java枚举默认是线程安全的,而且防止了反射攻击。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { } } ``` 7. **登记式/注册...

Global site tag (gtag.js) - Google Analytics