用私有构造器或者枚举类型强化Singleton
2019-05-10 06:05:25来源:博客园 阅读 ()
参考Effective Java第三版 Joshua J. Bloch
参与编写JDK的大佬,上次看Collections的源码时看见了他的名字,然后翻了翻书,竟然就是他写的!
1.常见的一种:
public class Singleton {
private static final Singleton INSTANCE=new Singleton();
private Singleton(){ //如果没有判断,可以通过反射使用构造函数创建对象,然后就不是单例了 if (INSTANCE!=null){ //throw Exception } }
public static Singleton getInstance(){ return INSTANCE; }
public void doSomething(){ //... } }
通过反射:可以看到singleton的两个实例不是同一个。
class Main {
public static void main(String[] args) { testSingleton(); }
private static void testSingleton() {
Singleton s1 = Singleton.getInstance(); Class<Singleton> clazz = Singleton.class; try { Constructor<Singleton> constructor = clazz.getDeclaredConstructor(new Class[]{}); constructor.setAccessible(true); Singleton s2 = constructor.newInstance(new Class[]{}); System.out.println(s1 == s2); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
2.用枚举:推荐的方法
优点:引用Effective Java的话:简洁,无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。单元素的枚举类常是实现Singleton的最佳方法。如果Singleton必须扩展一个超类,而不是扩展Enum时,不适宜使用这个方法。
public enum EnumSingleton {
INSTANCE; public void doSomething(){ //... } }
按照第一个测试的时候会报错的。
3.序列化
序列化有个问题就是,反序列化时会创建一个新的实例,破坏单例,下面让原来那个类实现Serializable接口。
public class Singleton implements Serializable { private static final Singleton INSTANCE=new Singleton(); private Singleton(){ if (INSTANCE!=null){ try { throw new Exception("INSTANCE已存在!"); } catch (Exception e) { e.printStackTrace(); } } } public static Singleton getInstance(){ return INSTANCE; } public void doSomething(){ //... } }
测试一下:Effective Java的第9条 使用try-with-resources优于try-finally,关闭资源的时候。
private static void testSerializableSingleton() {
File file=new File("singleton.out"); try(ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(file)); ObjectInputStream in=new ObjectInputStream(new FileInputStream(file))){ out.writeObject(Singleton.getInstance()); Singleton singleton= (Singleton) in.readObject(); System.out.println(singleton == Singleton.getInstance()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
打印的结果是false,说明序列化破化了单例,因为反序列化是反射调用了无参构造函数。
解决方法:在类里加入这个方法,详见Effective Java第89条
private Object readResolve() { return INSTANCE; }
然后结果就是true了。
原文链接:https://www.cnblogs.com/KuroNJQ/p/10833947.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Tomcat控制台乱码问题
下一篇:1-2 斐波那契数列的和
- 构造函数中的this()和super() 2020-06-10
- Java连载120-反射机制获取构造方法和父类、父接口 2020-06-05
- HashMap:源代码(构造方法、put、resize、get、remove、rep 2020-06-04
- Java连载119-反编译类的某个方法已经构造方法 2020-06-01
- Spring Boot 开发集成 WebSocket,实现私有即时通信系统 2020-05-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash