为了防止通过反序列化得到多个对象,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
分享到:
相关推荐
NULL 博文链接:https://java--hhf.iteye.com/blog/2171034
主要实现了枚举类创建单例后,将结果返回给前端。 看过一些其他人的实现,都比较麻烦。这是结合一些博主的代码,摸索出来的比较方便的方案。 缺点就是 多线程下会不会有 问题,期待大神的回复。
帮助大家复习java基础知识其中有 hashCode 2 toString 2 finalize 2 用已学知识做出简单的房屋出租系统 3 类方法使用注意事项和细节讨论 4 main()方法 4 代码块 4 代码块使用注意事项和细节 5 单例模式 6 final...
单例设计模式:★★★★★ 156 工厂模式★★★★★ 159 抽象工厂模式★★★★★ 163 建造者模式 170 原型模式 177 适配器模式 182 桥接模式 188 过滤器模式 192 组合模式 193 装饰器模式★★★★★ 196 外观模式 201...
3.如果枚举类中只有一个对象,则可以作为单例模式的实现方式。 二、如何定义枚举类 方式一:Jdk5.0之前,自定义枚举类 方式二:jdk5.0之后,可以使用enum关键字定义枚举类 三、Enum类的主要方法: 四、使用enum...
Java面向对象 1 1 学习方法与要求 1 2 面向对象语言与面向过程语言的区别 7 3 面向对象?什么对象? 8 4 什么是类? 9 5 如何创建一个类Class? 10 6 如何使用类创建对象 10 7 引用与实例 11 8 实例属性与实例方法 ...
android-singleton-test Android 上各种单例实现的简单演示和性能测试。 在 Android Studio 中打开项目并将其作为 Android 仪器测试运行。 以下是在少数设备上的测试运行结果。 Enum 或 Holder Class 实现总是最快的...
请叫我大师兄 Java Note Project 项目结构目录 bean 统一存放一些测试使用的model的bean,enum... 设计模式 简要说明 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计...
#studio 快速生成 单例模式的插件#单例的六种生成方式:LazyUnSafe,LazySafe,Hungry,DoubleCheck,StaticInner,Enum;#安装预设1.Android studioFile->Settings..->Plugins-->Browse repositores..搜索SingletonTest...
Java Note Project 项目结构目录 bean 统一存放一些测试使用的model的bean,enum... 设计模式 简要说明 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了重用...
Resha 是用 Java 编写的快速且“不那么激进”的土耳其语词干分析器。 它使用由使用基于词素 n-gram 的统计语言模型生成的词干词典。 所以它返回一个词最可能的词干而不考虑相邻词。 ####主要特点 与其他可用于...
•一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽 象方法); •否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。 接口...
实现的,它负责将 <JAVA_HOME >/lib/ext或者由系统变量-Djava.ext.dir指定位置 中的类库 加载到内存中。开发者可以直接使用标准扩展类加载器。 3. 系统类 (应用类)加载器(Application ...
###Ship Factory Increment ( ),它实现了工厂方法和抽象工厂模式,添加了原型和单例模式。 ###类图: 请注意,添加了实现上述模式的 Enum 类型的 NavioManager 类。 这个类包含了每艘船的创建方法,每种类型的...