Principle

  1. Do not accept the default serialized form without first considering whether it is appropriate.  

    The default serialized form is likely to be appropriate if an object's physical representation is identical to its logical content.

    @serial tag tells the Javadoc utility to place this documentation on a special page that documents serialized forms.

    // Good candidate for default serialized form

    public class Name implements Serializable {

    /**

    * Last name. Must be non-null.

    * @serial

    */

    private final String lastName;

    /**

    * First name. Must be non-null.

    * @serial

    */

    private final String firstName;

    /**

    * Middle name, or null if there is none.

    * @serial

    */

    private final String middleName;

    ... // Remainder omitted

    }

  2. Even if you decide that the default serialized form is appropriate, you often must provide a readObject method to ensure invariants and security.  

    Using the default serialized form when an object's physical representation differs substantially from its logical data content has four disadvantages:

    1. It permanently ties the exported API to the current internal representation.
    2. It can consume excessive space.
    3. It can consume excessive time. (Topology graph traversal)
    4. it can cause stack overflow. (Depends on JVM implementation)

    Inconsistent demo for logic data and physical representation

    // Awful candidate for default serialized form

    public final class StringList implements Serializable {

    private int size = 0;

    private Entry head = null;

    private static class Entry implements Serializable {

    String data;

    Entry next;

    Entry previous;

    }

    ... // Remainder omitted

    }

    Revised version of StringList containing writeObject and readObject methods implementing this serialized form.

    public class StringList implements Serializable {

    /**

    * The serial version UID of the object.

    */

    private static final long serialVersionUID = 7533856777949584383L;

    private transient int size = 0;

    private transient Entry head = null;

    private transient Entry tail = null;

    // No longer Serializable!

    private static class Entry {

    String data;

    Entry next;

    @SuppressWarnings("unused")

    Entry previous;

    }

    // Appends the specified string to the list

    public final void add(String s) {

    Entry e = new Entry();

    e.data = s;

    if (null == head) {

    tail = head = e;

    } else {

    tail.next = e;

    tail.next.previous = tail;

    tail = tail.next;

    }

    size++;

    }

    /**

    * Serialize this {@code StringList} instance.

    *

    * @serialData The size of the list (the number of strings it contains) is

    * emitted ({@code int}), followed by all of its elements (each

    * a {@code String}), in the proper sequence.

    */

    private void writeObject(ObjectOutputStream s) throws IOException {

    s.defaultWriteObject();

    s.writeInt(size);

    // Write out all elements in the proper order.

    for (Entry e = head; e != null; e = e.next)

    s.writeObject(e.data);

    }

    private void readObject(ObjectInputStream s) throws IOException,

    ClassNotFoundException {

    s.defaultReadObject();

    int numElements = s.readInt();

    // Read in all elements and insert them in list

    for (int i = 0; i < numElements; i++)

    add((String) s.readObject());

    }

    /*

    * (non-Javadoc)

    *

    * @see java.lang.Object#toString()

    */

    @Override

    public String toString() {

    StringBuilder sb = new StringBuilder();

    for (Entry it = head; it != null; it = it.next)

    sb.append(it.data);

    return sb.toString();

    }

    /**

    * @param args

    */

    public static void main(String[] args) {

    StringList sl = new StringList();

    for (int i = 0; i < 5; i++) {

    sl.add(String.valueOf(i));

    }

    System.out.println(sl);

    try {

    FileOutputStream fos = new FileOutputStream("t.tmp");

    ObjectOutputStream oos = new ObjectOutputStream(fos);

    oos.writeObject(sl);

    oos.close();

    FileInputStream fis = new FileInputStream("t.tmp");

    ObjectInputStream ois = new ObjectInputStream(fis);

    StringList sl2 = (StringList) ois.readObject();

    System.out.println("Desialized obj = " + sl2);

    } catch (FileNotFoundException e) {

    e.printStackTrace();

    } catch (IOException e) {

    e.printStackTrace();

    } catch (ClassNotFoundException e) {

    e.printStackTrace();

    }

    }

    // Remainder omitted

    }

  3. Before deciding to make a field nontransient, convince yourself that its value is part of the logical state of the object.  

    Note

    If all instance fields are transient, it is technically permissible to dispense with invoking defaultWriteObject and defaultReadObject, but it is not recommended. If there are nontransient fields to be added in the class due to failed to invoke defaultReadObject, the deserialization would fail with a StreamCorruptedException.

    Every instance field that can be made transient should be made so since not labeled transient will be serialized when the defaultWriteObject method is invoked.

  4. if you are using the default serialized form.
    1. Transient field will be initialized as their default value (e.g. null, 0, false).
    2. If the default value cannot be acceptable you should provide readObject method and invoke defaultReadObject method and then restores transient fields to acceptable values (Item 76).
    3. Transient field can be lazily initialized the first time they are used (Item 71) .
  5. You must impose any synchronization on object serialization that you would impose on any other method that reads the entire state of the object. You must ensure that it adheres to the same lock-ordering constraints as other activity,  

    // writeObject for synchronized class with default serialized form

    private synchronized void writeObject(ObjectOutputStream s)

    throws IOException {

    s.defaultWriteObject();

    }

  6. Regardless of what serialized form you choose, declare an explicit serial version UID in every serializable class you write.

    private static final long serialVersionUID = randomLongValue ;

    If you modify an existing class that lacks a serial version UID, and you want the new version to accept existing serialized instances, you must use the value that was automatically generated for the old version. Or InvalidClassException will be invoked when there is a serialized object to be deserialized by the new modified the class.

Summary

when you have decided that a class should be serializable (Item 74), think hard about what the serialized form should be. Use the default serialized form only if it is a reasonable description of the logical state of the object; otherwise design a custom serialized form that aptly describes the object. You should allocate as much time to designing the serialized form of a class as you allocate to designing its exported methods (Item 40). Just as you cannot eliminate exported methods from future versions, you cannot eliminate fields from the serialized form; they must be preserved forever to ensure serialization compatibility. Choosing the wrong serialized form can have a permanent, negative impact on the complexity and performance of a class.

Effective Java 75 Consider using a custom serialized form的更多相关文章

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

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

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

  3. Effective Java 目录

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

  4. 【Effective Java】阅读

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

  5. Effective Java 第三版—— 87. 考虑使用自定义序列化形式

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  6. Effective Java 第三版—— 86. 非常谨慎地实现SERIALIZABLE接口

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  7. Effective java笔记8--序列化

    对象的序列化(object serialization)API,它提供了一个框架,用来将对象编码成一个字节流,以及从字节流编码中重新构建对象. 一.谨慎地实现Serializable     要想使一 ...

  8. Effective Java 44 Write doc comments for all exposed API elements

    Principle You must precede every exported class, interface, constructor, method, and field declarati ...

  9. EFFECTIVE JAVA 第十一章 系列化

    EFFECTIVE  JAVA  第十一章  系列化(将一个对象编码成一个字节流) 74.谨慎地实现Serializable接口 *实现Serializable接口付出的代价就是大大降低了“改变这个类 ...

随机推荐

  1. [pyhton]python内建方法

    撸一遍python的内建方法 这样做的好处就是:我如果要完成一个功能的时候,如果能用内建方法完成,就用内建方法.这样可以提高效率,同时使自己的代码更加优雅.哎呦?那岂不是撸完就是python高手了?我 ...

  2. IIS Express魔法堂:解除localhost域名的锁定

    一.前言   单点登录是通过域名从cookie中获取登录信息,然后再根据cookie的键值对获取用户信息.但由于通过IIS Express调试应用时默认使用localhost作为域名且无法直接修改,导 ...

  3. mac ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

    好久不用mysql,今天突然想用的时候, mysql -uroot -p 直接报了下面的错误 ERROR 2002 (HY000): Can't connect to local MySQL serv ...

  4. 图片轮播(左右切换)--JS原生和jQuery实现

    图片轮播(左右切换)--js原生和jquery实现 左右切换的做法基本步骤跟 上一篇文章  淡入淡出 类似,只不过修改了一些特定的部分 (1)首先是页面的结构部分 对于我这种左右切换式 1.首先是个外 ...

  5. 在Linux上安装Oracle RAC 12 c(12.1) 虚拟机,一步一步向导

    Oracle RAC 12 c(12.1)在Linux上安装虚拟机,一步一步向导 今天我们将看到如何安装 12 c版本1 RAC(真正的应用程序集群)数据库2 Linux 64位的虚拟机 使用VMWa ...

  6. C# 通过自定义特性 实现根据实体类自动创建数据库表

    .Net新手通常容易把属性(Property)跟特性(Attribute)搞混,其实这是两种不同的东西 属性指的类中封装的数据字段:而特性是对类.字段.方法和属性等元素标注的声明性信息 如下代码(Id ...

  7. [CLR via C#]16. 数组

    数组是允许将多个数据项当作一个集合来处理的机制.CLR支持一维数组.多维数组和交错数据(即由数组构成的数组).所有数组类型都隐式地从System.Array抽象类派生,后者又派生自System.Obj ...

  8. 【Unity】12.5 Navmesh Obstacle组件

    开发环境:Win10.Unity5.3.4.C#.VS2015 创建日期:2016-05-09 一.简介 在大多数游戏情景中,可行进的区域往往不是完全不变的.比如被破坏的路.桥等将不再允许通过.那么, ...

  9. HDU 2577---How to Type

    HDU  2577 Description Pirates have finished developing the typing software. He called Cathy to test ...

  10. [小北De编程手记] : Selenium For C# 教程目录

    写<Selnium For C#>系列文章的初衷是因为有很多朋友问我应该从哪里开始学习自动化测试,于是就为大家写下了这个系列的文章,希望对你有些帮助吧.而我想表达的是Selenium(同时 ...