`
837062099
  • 浏览: 112650 次
  • 性别: 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实现单例模式的方法来读取配置文件

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

    Java实现多种单例模式

    以下是Java实现的六种单例模式的详细解释: 1. 懒汉式(Lazy Initialization): 这种方式延迟了单例对象的初始化,直到第一次被请求时。例如,`SingleInstance1.java`可能就实现了这种方式。代码通常包含一个私有...

    java单例模式实例

    在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们来看**懒汉式(Lazy Initialization)**。这种实现方式是在类被首次请求时才创建单例对象,延迟...

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

    在Java中,通常有三种常见的单例实现方式:懒汉式单例、饿汉式单例和登记式单例。 1. **懒汉式单例**: 懒汉式单例的特点是在类加载时不创建实例,而是等到第一次调用`getInstance()`方法时才创建。这样可以延迟...

    java中的单例模式

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

    单例模式各种实现方式

    每种实现方式都有其特点和适用场景,开发者应根据实际需求选择合适的单例实现。在实际项目中,还要考虑性能、线程安全以及代码可读性等因素。例如,如果项目中对性能要求较高,可以优先考虑静态内部类或枚举实现;...

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

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

    单例模式Java实现

    1. **饿汉式(静态常量)**:这是最简单的单例实现方式,它在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快,且线程安全。 ```java public class Singleton { private static final Singleton ...

    Java 单例模式 工具类

    这是最简单的单例实现,它在类加载时就完成了初始化,因此是线程安全的。 ```java public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static...

    二十三种设计模式Java版之单例模式

    在实际应用中,应根据项目需求选择合适的单例实现方式。例如,如果对性能要求较高且不需要延迟初始化,饿汉式可能是个好选择;而如果希望在多线程环境下保证安全并避免同步开销,DCL或枚举方式更为合适。在开发过程...

    java设计模式之单例模式.zip

    在Java中实现单例模式有多种方法: 1. **饿汉式(静态常量)**:在类加载时就完成了初始化,所以没有线程安全问题,但这种实现方式无法实现延迟加载。 ```java public class Singleton { private static final ...

    Java实现单例设计模式方法解析

    饿汉式单例是最简单的一种单例实现方式,它在类加载时就创建了单例对象。其优点是线程安全,但缺点是浪费资源,因为即使不使用单例对象,它也会被创建。 示例代码: 方式一:枚举方式获得单例对象 enum Singleton...

    java-单例模式几种写法

    这是最简单的单例实现,它在类加载时就创建了实例,线程安全。 ```java public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static ...

    Java的单例设计模式

    4. 避免序列化破坏单例:如果单例实现了`Serializable`接口,序列化和反序列化可能导致多个实例。为此,可以在单例类中添加`readResolve()`方法来返回唯一的实例。 总的来说,Java的单例设计模式是一种强大的工具,...

    Java静态内部类实现单例过程

    Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在Java中,有多种实现单例的方式,包括饿汉式、懒汉式、双重...在实际开发中,应根据具体需求选择合适的单例实现方式。

    java单例模式的例子

    下面我们将深入探讨Java单例模式的概念、实现方式以及其优缺点。 **单例模式的概念** 单例模式的核心思想是限制类的实例化,只允许创建一个对象,同时提供一个全局访问点,使得这个唯一的实例可以被任何需要的地方...

Global site tag (gtag.js) - Google Analytics