Effective Java 77 For instance control, prefer enum types to readResolve
The readResolve feature allows you to substitute another instance for the one created by readObject [Serialization, 3.7].
If the class of an object being deserialized defines a readResolve method with the proper declaration, this method is invoked on the newly created object after it is deserialized. The object reference returned by this method is then returned in place of the newly created object. In most uses of this feature, no reference to the newly created object is retained, so it immediately becomes eligible for garbage collection.
public class Elvis implements Serializable {
/**
* The version UID for the serial version object.
*/
private static final long serialVersionUID = 4285474589312744336L;
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
// readResolve for instance control - you can do better!
private Object readResolve() {
// Return the one true Elvis and let the garbage collector take care of the Elvis impersonator.
return INSTANCE;
}
public static void main(String[] args) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(os);
oos.writeObject(Elvis.INSTANCE);
oos.close();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
Elvis e = (Elvis) ois.readObject();
System.out.printf("Elvis is %s the one used before? ",
e == Elvis.INSTANCE? "": "not");
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Note
If you depend on readResolve for instance control, all instance fields with object reference types must be declared transient. If a singleton contains a nontransient object reference field, the contents of this field will be deserialized before the singleton's readResolve method is run.
A demo for attack to secure a reference to the deserialized object before its readResolve method is run.
First, write a "stealer" class that has both a readResolve method and an instance field that refers to the serialized singleton in which the stealer "hides." In the serialization stream, replace the singleton's nontransient field with an instance of the stealer. You now have a circularity: the singleton contains the stealer and the stealer refers to the singleton.
Because the singleton contains the stealer, the stealer's readResolve method runs first when the singleton is deserialized. As a result, when the stealer's readResolve method runs, its instance field still refers to the partially deserialized (and as yet unresolved) singleton.
The stealer's readResolve method copies the reference from its instance field into a static field, so that the reference can be accessed after the readResolve method runs. The method then returns a value of the correct type for the field in which it's hiding. If it didn't do this, the VM would throw a ClassCastException when the serialization system tried to store the stealer reference into this field.
// Broken singleton - has nontransient object reference field!
public class Elvis implements Serializable {
private static final long serialVersionUID = 1L;
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
private String[] favoriteSongs = { "Hound Dog", "Heartbreak Hotel" }; // favorite field
public void printFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
}
public class ElvisStealer implements Serializable {
static Elvis impersonator;
private Elvis payload;
private Object readResolve() {
// Save a reference to the "unresolved" Elvis instance
impersonator = payload;
// Return an object of correct type for favorites field
return new String[] { "A Fool Such as I" };
}
private static final long serialVersionUID = 0;
}
You could fix the problem by declaring the favorites field transient, but you're better off fixing it by making Elvis a single-element enum type (Item 3).
// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
private String[] favoriteSongs = { "Hound Dog", "Heartbreak Hotel" };
public void printFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
}
The accessibility of readResolve is significant.
If you place a readResolve method on a final class, it should be private.
If you place a readResolve method on a nonfinal class, you must carefully consider its accessibility.
If it is private, it will not apply to any subclasses.
If it is package-private, it will apply only to subclasses in the same package.
If it is protected or public, it will apply to all subclasses that do not override it.
If a readResolve method is protected or public and a subclass does not overriden it, deserializing a serialized subclass instance will produce a superclass instance, which is likely to cause a ClassCastException.
Summary
You should use enum types to enforce instance control invariants wherever possible. If this is not possible and you need a class to be both serializable and instance-controlled, you must provide a readResolve method and ensure that all of the class's instance fields are either primitive or transient.
Effective Java 77 For instance control, prefer enum types to readResolve的更多相关文章
- Effective Java 31 Use instance fields instead of ordinals
Principle Never derive a value associated with an enum from its ordinal; store it in an instance fie ...
- Effective Java 19 Use interfaces only to define types
Reason The constant interface pattern is a poor use of interfaces. That a class uses some constants ...
- Effective Java 37 Use marker interfaces to define types
Marker interface is an interface that contains no method declarations, but merely designates (or &qu ...
- Effective Java Index
Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...
- 《Effective Java》读书笔记 - 11.序列化
Chapter 11 Serialization Item 74: Implement Serializable judiciously 让一个类的实例可以被序列化不仅仅是在类的声明中加上" ...
- Effective Java 目录
<Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...
- 【Effective Java】阅读
Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...
- Effective Java 第二版 Enum
/** * Effective Java 第二版 * 第30条:用enum代替int常量 */ import java.util.HashMap;import java.util.Map; publi ...
- Effective Java Chapter4 Classes and Interface
MInimize the accessibility of classes and members 这个叫做所谓的 information hiding ,这么做在于让程序耦合度更低,增加程序的健壮性 ...
随机推荐
- "浅谈Android"第二篇:活动(Activity)
距离上一篇文章,过去有半个多月了,在此期间忙于工作,疏于整理和总结,特此写下这篇博文,来谈谈自己对Activity的理解.总所周知,Activity组件在Android中的重要性不言而喻,我们 ...
- sql server 调用webservice
sql server版本2008以上,应该都可以 更改服务器配置 sp_configure ; GO RECONFIGURE; GO sp_configure ; GO RECONFIGURE; GO ...
- Mysql的“Limit”操作
Limit操作: ,; #返回第6-15行数据 ; #返回前5行 ,; #返回前5行 性能优化: 基于MySQL5.0中limit的高性能,我对数据分页也重新有了新的认识.测试SQL语句1: Sele ...
- javaScript一些函数包括调试方法(二)
Number():设法把括号里面的值,转换成一个数,转换不了为数字的话,就返回NaN. 注意:Number()函数,会拒绝任何包含,非数字字符的字符串(阿拉伯数字.一个有效的小数位.+.-符号是允许的 ...
- P6 Enterprise Project Portfolio Contract Management
Find documentation for Primavera products here: Primavera Cloud Services Primavera Prime Primavera P ...
- VS用法总结
工欲善其事,必先利其器,关于VS的“即时窗口”的使用: 打开“即时窗口”的快捷键是:Ctrl + Alt + I. 要在“即时窗口”中打印查看打印输出结果,必须按如下步骤设置:[工具]→[选项]→[调 ...
- 重新想象 Windows 8.1 Store Apps (87) - TTS: Speak Text, Speak SSML
[源码下载] 重新想象 Windows 8.1 Store Apps (87) - TTS: Speak Text, Speak SSML 作者:webabcd 介绍重新想象 Windows 8.1 ...
- 野比的示波器案例(Winfrom用户控件)
使用该用户控件做的效果图,如果数据正确,可实现 波形.直线.等等效果图...... 对于本程序的认识还是不够深彻.如果有其他方法或算法,欢迎讨论下.将我所能理解的代码都再次标识了一番. ------- ...
- C语言范例学习02
第二章 指针 算是重点吧,这也是C语言的特色啊,直接访问物理存储. 重点: 指针就是一个存放它指向变量地址的变量,好绕口. 区分*在定义是与引用是的作用. 区分*.&的不同. 指针 ...
- hdu 1518 拼正方形
本题来自:http://acm.hdu.edu.cn/showproblem.php?pid=1518 题意:输入几个长度,判断能否拼成正方形. 以下部分参考了网友代码,终于ac啦. #include ...