枚举增强单例模式的可靠性

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/java2000_net/archive/2009/03/12/3983958.aspx#

我们常用的构造单例模式(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)

小结:可见,只有第三种枚举的方法才是最安全的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值