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

java enum实现的单例

阅读更多
为了防止通过反序列化得到多个对象,EJ提倡使用enum实现单例:
关于枚举的对象为什么可以反序列化:可以看Enum类的如下方法:
 /**
      * prevent default deserialization
      */
    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
            throw new InvalidObjectException("can't deserialize enum");
    }

    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test {
	public static void main(String[] args) throws Exception {
		Singleton d1 = Singleton.INSTANCE;
		d1.setName("a fucker.");
		System.out.println(d1);
		
		FileOutputStream fos = new FileOutputStream("out.data");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(d1);
		fos.close();
		oos.close();
		
		FileInputStream fis = new FileInputStream("out.data");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Object o = ois.readObject();
		fis.close();
		ois.close();
		
		Singleton d2 = (Singleton)o;
		
		System.out.println(d2);
		System.out.println(d1 == d2);
	}
}
enum Singleton implements Serializable {
	
	INSTANCE;
	
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "[" + name + "]";
	}
}

因为一个enum常量(这里是INSTANCE)代表了一个enum的实例,enum类型只能有这些常量实例。标准保证enum常量(INSTANCE)不能被克隆,也不会因为反序列化产生不同的实例,想通过反射机制得到一个enum类型的实例也不行的。


如果用一般方式写单例模式,该单例类如果实现了Serializable接口,则必须添加readResolve()方法,当然我认为按照Enum类的设计在 readObject(ObjectInputStream in)中抛出异常也可以有效防止反序列化:
public class Singleton {
	
	private static volatile Singleton st;

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

	/**
	 * 反序列化时内存Hook这段代码
	 * @return
	 */
	private Object readResolve() {
		return st;
	}
}


 ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
 ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

这两个方法可以理解为序列化和反序列化过程的入口和出口。writeReplace()返回的对象,就是要被序列化的对象,我们有机会在序列化前把这个对象给换成我们确定好的那个(如果不是“故意捣乱”,暂时没想到有什么用);而readResolve()方法就是在反序列化完成得到对象前,把这个对象给换成我们确定好的那个。

明白了吧?为了防止有人恶意通过序列化的机制破坏定义好的单例,我们就需要自己实现readResolve()方法,把单例定义的唯一实现在这个方法中返回。
一般单例处理方法:http://www.blogjava.net/dreamstone/archive/2006/11/04/79026.html
恶汉式的单例也有问题:http://www.ibm.com/developerworks/cn/java/j-lo-clobj-init/index.html
分享到:
评论

相关推荐

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

    NULL 博文链接:https://java--hhf.iteye.com/blog/2171034

    枚举类实现单例,并且解决序列化给前端展示的问题.zip

    主要实现了枚举类创建单例后,将结果返回给前端。 看过一些其他人的实现,都比较麻烦。这是结合一些博主的代码,摸索出来的比较方便的方案。 缺点就是 多线程下会不会有 问题,期待大神的回复。

    观看韩顺平学习整理java的笔记到异常

    帮助大家复习java基础知识其中有 hashCode 2 toString 2 finalize 2 用已学知识做出简单的房屋出租系统 3 类方法使用注意事项和细节讨论 4 main()方法 4 代码块 4 代码块使用注意事项和细节 5 单例模式 6 final...

    Java基础知识点总结.docx

    单例设计模式:★★★★★ 156 工厂模式★★★★★ 159 抽象工厂模式★★★★★ 163 建造者模式 170 原型模式 177 适配器模式 182 桥接模式 188 过滤器模式 192 组合模式 193 装饰器模式★★★★★ 196 外观模式 201...

    Java枚举类的使用与注解

    3.如果枚举类中只有一个对象,则可以作为单例模式的实现方式。 二、如何定义枚举类 方式一:Jdk5.0之前,自定义枚举类 方式二:jdk5.0之后,可以使用enum关键字定义枚举类 三、Enum类的主要方法: 四、使用enum...

    JAVA面向对象详细资料

    Java面向对象 1 1 学习方法与要求 1 2 面向对象语言与面向过程语言的区别 7 3 面向对象?什么对象? 8 4 什么是类? 9 5 如何创建一个类Class? 10 6 如何使用类创建对象 10 7 引用与实例 11 8 实例属性与实例方法 ...

    android-singleton-test:Android上各种单例实现的简单演示和性能测试

    android-singleton-test Android 上各种单例实现的简单演示和性能测试。 在 Android Studio 中打开项目并将其作为 Android 仪器测试运行。 以下是在少数设备上的测试运行结果。 Enum 或 Holder Class 实现总是最快的...

    JavaNote:java es番石榴jdk jdk8 jsonLombokmd线程jvm spring mvc vertx设计模式风暴

    请叫我大师兄 Java Note Project 项目结构目录 bean 统一存放一些测试使用的model的bean,enum... 设计模式 简要说明 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计...

    SingletonTest:快速生成单例模式的预设

    #studio 快速生成 单例模式的插件#单例的六种生成方式:LazyUnSafe,LazySafe,Hungry,DoubleCheck,StaticInner,Enum;#安装预设1.Android studioFile->Settings..->Plugins-->Browse repositores..搜索SingletonTest...

    谷歌师兄的leetcode刷题笔记-JavaNote:javaesguavajdkjdk8jsonlombokmdthreadjvmsprin

    Java Note Project 项目结构目录 bean 统一存放一些测试使用的model的bean,enum... 设计模式 简要说明 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了重用...

    resha-turkish-stemmer:一种快速且攻击性较低的 Java 土耳其语词干分析器

    Resha 是用 Java 编写的快速且“不那么激进”的土耳其语词干分析器。 它使用由使用基于词素 n-gram 的统计语言模型生成的词干词典。 所以它返回一个词最可能的词干而不考虑相邻词。 ####主要特点 与其他可用于...

    【05-面向对象(下)】

    •一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽 象方法); •否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。 接口...

    day020-继承加强和设计模式代码和笔记.rar

    实现的,它负责将 <JAVA_HOME >/lib/ext或者由系统变量-Djava.ext.dir指定位置 中的类库 加载到内存中。开发者可以直接使用标准扩展类加载器。 3. 系统类 (应用类)加载器(Application ...

    FabricanaviosV2

    ###Ship Factory Increment ( ),它实现了工厂方法和抽象工厂模式,添加了原型和单例模式。 ###类图: 请注意,添加了实现上述模式的 Enum 类型的 NavioManager 类。 这个类包含了每艘船的创建方法,每种类型的...

Global site tag (gtag.js) - Google Analytics