书上分别说了以下三种
1)将公有静态成员做成final域享有特权的客户端可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。
package com.lzw.singleton1; import java.lang.reflect.Constructor; /** * * 单例实现1 * <p> * 公有静态成员是个public final域 * <p> * 为防止client利用反射调用私有改造函数,所以在创建第二个实例的时候抛出了异常 * * @author troyli * */ public class Singleton1 { public static final Singleton1 INSTANCE = new Singleton1(); // 私有改造函数 private Singleton1() { if (INSTANCE != null) { throw new IllegalArgumentException("不存在第二个实例对象……"); } } // 其他方法实现 public void otherMethod() { System.out.println("call otherMethod"); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String args[]) throws Exception { Singleton1 singleton = Singleton1.INSTANCE; singleton.otherMethod(); // 利用反射调用私有构造器 Constructor[] arrayConstructor = singleton.getClass() .getDeclaredConstructors(); for (Constructor constructor : arrayConstructor) { // 调用setAccessible(true); constructor.setAccessible(true); // 实例化,这里一定会抛出异常 constructor.newInstance(); } } }
问题:为什么会抛出异常(不存在第二个实例对象……),这里我们分析一下代码的执行顺序。
①JVM 装载类的静态成员变量:public static final Singleton1 INSTANCE;
②执行入口方面main;
③获取实例对象:Singleton1 singleton = Singleton1.INSTANCE;也就会执行private Singleton1(){……}
④执行newInstatnce:constructor.newInstance();就会是在已经有一个对象的时候重新调用private Singleton1(){……},于是就会抛出异常。
2)将公有静态成员做成final域和将公有成员做成静态工厂方法时,为了使Singleton类变成可序列化的,仅仅在声明上加上“implements Serializable”是不够的。
为了维护并保证Singleton,必须声明所有实例域都是瞬时的(transient),并提供一个readResolve方法。否则,每次反序列化一个序列化的实例时,都会创建一个新的实例。
package com.lzw.singleton2; import java.io.Serializable; /** * *单例实现2 *<p> * 公有的成员为静态工厂方法 *<p> * 序列化时,要实现readResolve方法,防止反序列化出新的实例(这个应该怎么测试呢???) * *@author troyli * */ public class Singleton2 implements Serializable { // 私有static Instance private static final Singleton2 INSTANCE = new Singleton2(); // 私有构造函数 private Singleton2() { } // 获取单例方法 public static Singleton2 getInstance() { return INSTANCE; } // 其他方法 public void otherMethod() { // } // 必须提供该方法,以便重新指定反序列化得到的对象. private Object readResolve() { return INSTANCE; } }
这点对我是全新的东西,因此也在积累中……
3)单元素枚举类型更加简洁、无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击时;它已经成为实现Singleton的最佳方法。
package com.lzw.singleton3; import java.lang.reflect.Constructor; /** * *枚举实现单例 *<p> * 目前最好的方式,避免了反射的攻击和序列化的问题 * *<pre> * 射调用枚举私有构造函数测试结果: * Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.lzw.singleton3.Singleton3.main(Singleton3.java:41) *</pre> * *@author troyli * */ public class Singleton3 { enum EnumSingleton { INSTANCE; public void otherMethod() { } } // 测试,是否可以反射生成枚举 public static void main(String args[]) throws Exception { // 利用反射调用私有构造器 Constructor[] arrayConstructor = EnumSingleton.INSTANCE.getClass() .getDeclaredConstructors(); for (Constructor constructor : arrayConstructor) { // 调用setAccessible(true),设置为可以访问; constructor.setAccessible(true); // 实例化,这里一定会抛出异常 constructor.newInstance(); } } }
可以看上面的第一种的问题解析,这里不再重复。
虽然这种方法目前还没有被广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。
相关推荐
Singleton拥有一个私有构造函数,确保用户无法通过new直接实例化它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance()方法负责检验并实例化自己,然后存储在静态成员变量中...
简单的单例模式举例Singleton 分为恶汉式 懒汉式
java singleton 不解释不解释不解释不解释
java Singleton单例模式 java Singleton单例模式
Java常用设计模式(SingleTon、FactoryMethod、AbstractFactory)
Java的Singleton模式代码(免资源分),你会发现Java的Singleton模式真的很有趣,原来程序还可以这样写。
Item 3: Enforce the singleton property with a private constructor or an enum type Item 4: Enforce noninstantiability with a private constructor Item 5: Prefer dependency injection to hardwiring ...
1、没有构造函数(DEFINE_SINGLETON_DEFAULT); 2、有构造函数,构造函数没有参数(DEFINE_SINGLETON_CONSTRUCT_NO_PARAM); 3、有构造函数,构造函数有没有参数版本(DEFINE_SINGLETON_CONSTRUCT_WITH_DEFAULT)...
6.8.3 枚举类的属性、方法和构造器 220 6.8.4 实现接口的枚举类 223 6.8.5 包含抽象方法的枚举类 224 6.9 对象与垃圾回收 225 6.9.1 对象在内存中的状态 226 6.9.2 强制垃圾回收 227 6.9.3 finalize方法 228 ...
singleton pattern 的定义 主要应用方法 优缺点 通过代码 具体分析解释
Singleton在Java中的应用,实例介绍
Java的几个练习,reflect,singleton,DomAndSax
C++完美实现Singleton模式
1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入bbbwlirbbb,输出...
设计模式之Singleton(单态
单例模式 Singleton 单例模式线程安全问题和拓展
在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这可以节省一笔很大的系统开销。 2、省去了new操作符,降低了系统内存的使用频率...
单例模式(Singleton)
c++ singleton单例模式
1.寂寞的Singleton 2. 当Singleton遇见多线程 4.安全发布 6. 讨论的延续 1. JavaWorld章:Double-checked l