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的更多相关文章

  1. 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 ...

  2. 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 ...

  3. Effective Java 37 Use marker interfaces to define types

    Marker interface is an interface that contains no method declarations, but merely designates (or &qu ...

  4. 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 ...

  5. 《Effective Java》读书笔记 - 11.序列化

    Chapter 11 Serialization Item 74: Implement Serializable judiciously 让一个类的实例可以被序列化不仅仅是在类的声明中加上" ...

  6. Effective Java 目录

    <Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...

  7. 【Effective Java】阅读

    Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...

  8. Effective Java 第二版 Enum

    /** * Effective Java 第二版 * 第30条:用enum代替int常量 */ import java.util.HashMap;import java.util.Map; publi ...

  9. Effective Java Chapter4 Classes and Interface

    MInimize the accessibility of classes and members 这个叫做所谓的 information hiding ,这么做在于让程序耦合度更低,增加程序的健壮性 ...

随机推荐

  1. 2 Servlet基础

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 1. 从浏览器访问Servlet的流程 刚才发现,这里的图片不能正常显示,所以我给个链接,大家可以下载下来看从浏 ...

  2. Direct3D11学习:(零)常见问题及解决方法整理

    转载请注明出处:http://www.cnblogs.com/Ray1024   一.概述 在D3D11学习的这个系列中,单独写一篇文章来记录自己学习过程中遇到的问题及最后的解决方法. 这篇文章的目的 ...

  3. js-二维数组和多维数组

    一.二维数组的表示 myarray[][] 二.二维数组的定义 方法一: var a = new Array(); for(var i=0;i<3;i++){ //一维长度为3 a[i] = n ...

  4. 基于HTML5技术的电力3D监控应用(四)

    回答了知乎问题较长,一些使用WebGL的经验,作为新的一篇: 正好逛到这个问题,正好是2013年底,正好最近基于的HT for Web 3D做的电力项目收尾,正好用到的就是WebGL技术,因此说说自己 ...

  5. 我写的一个ExcelHelper通用类,可用于读取或生成数据

    读取或生成EXCEL数据的方法有很多,一般常见的有: 1.通过OFFICE EXCEL组件,优点:读取与生成EXCEL文件方便,缺点:服务器上必须安装OFFICE软件,且进程无法及时释放 2.通过第三 ...

  6. hibernate集成

    hibernate是一个优秀的持久化框架负责简化将对象保存到数据库中,或从数据库中读取数据并封装到对象的工作.hibernate通过简单配置和编码即可替代jdbc繁琐的程序代码. 下面是集成hiber ...

  7. Scrum4.0+5.0 数独游戏

    1.题目: 1.准备看板. 形式参考图4. 2.任务认领,并把认领人标注在看板上的任务标签上. 先由个人主动领任务,PM根据具体情况进行任务的平衡. 然后每个人都着手实现自己的任务. 3.为了团队合作 ...

  8. U3D自定义Inspector项未触发保存事件的解决方案

    1.问题描述与解决方案 1.1.说明 应该只有起步做U3D编辑器插件的部分同行需要了解本文. 该问题源于在做UI插件的时候,发现Inspector面板上手动修改值后,没有触发U3D编辑器本身的修改事件 ...

  9. Python入门笔记(17):错误、异常

    一.什么是错误,什么是异常,它们两者区别 这里解释如下:个人觉得很通俗易懂 错误是指在执行代码过程中发生的事件,它中断或干扰代码的正常流程并创建异常对象.当错误中断流程时,该程序将尝试寻找异常处理程序 ...

  10. bootstrap学习笔记(6)

    滚动监听        滚动监听有两种方式:        (1)通过属性控制        向想要滚动监听的元素添加如下属性data-spy="scroll",然后添加data- ...