《effective java》之十:序列化 博客分类: Java effective
程序员文章站
2024-02-15 08:51:04
...
第74条:谨慎地实现Serializable接口:
第75条:考虑使用自定义的序列化形式:
public final class StringList implements Serializable { private transient int size = 0; private transient Entry head = null; // No longer Serializable! private static class Entry { String data; Entry next; Entry previous; } // Appends the specified string to the list public final void add(String s) { // Implementation omitted } /** * 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()); } private static final long serialVersionUID = 93248094385L; // Remainder omitted }
第76条:保护性地编写readObject方法:
public final class Period implements Serializable { private Date start; private Date end; /** * @param start the beginning of the period * @param end the end of the period; must not precede start * @throws IllegalArgumentException if start is after end * @throws NullPointerException if start or end is null */ public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) throw new IllegalArgumentException(start + " after " + end); } public Date start() { return new Date(start.getTime()); } public Date end() { return new Date(end.getTime()); } public String toString() { return start + " - " + end; } // readObject method with defensive copying and validity checking - Page 306 // This will defend against BogusPeriod and MutablePeriod attacks. private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // Defensively copy our mutable components start = new Date(start.getTime()); end = new Date(end.getTime()); // Check that our invariants are satisfied if (start.compareTo(end) > 0) throw new InvalidObjectException(start + " after " + end); } }
第77条:对于实例控制,枚举类型优先于readResolve
还是那句话,单例模式用enum实现最好。
第78条:考虑用序列化代理代替序列化实例,序列化最佳实践:
首先,为可序列化类设计一个私有的静态嵌套类,精确表示外围类的实例的逻辑状态,被称作序列化代理。它有一个单独构造器,参数类型就是外围类。外围类和序列代理都实现Serializable接口。
其次,外围类增加writeReplace方法,返回序列代理对象
再次,外围类增加readObject方法,直接抛异常,防止攻击
最后,序列代理类提供readResolve方法,返回逻辑上相当的外围类实例。
public final class Period implements Serializable { private final Date start; private final Date end; /** * @param start * the beginning of the period * @param end * the end of the period; must not precede start * @throws IllegalArgumentException * if start is after end * @throws NullPointerException * if start or end is null */ public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) throw new IllegalArgumentException(start + " after " + end); } public Date start() { return new Date(start.getTime()); } public Date end() { return new Date(end.getTime()); } public String toString() { return start + " - " + end; } // Serialization proxy for Period class - page 312 private static class SerializationProxy implements Serializable { private final Date start; private final Date end; SerializationProxy(Period p) { this.start = p.start; this.end = p.end; } private static final long serialVersionUID = 234098243823485285L; // Any // readResolve method for Period.SerializationProxy - Page 313 private Object readResolve() { return new Period(start, end); // Uses public constructor } } // writeReplace method for the serialization proxy pattern - page 312 private Object writeReplace() { return new SerializationProxy(this); } // readObject method for the serialization proxy pattern - Page 313 private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("Proxy required"); } }
本人博客已搬家,新地址为:http://yidao620c.github.io/
推荐阅读
-
《effective java》之十:序列化 博客分类: Java effective
-
《effective java》之七:方法 博客分类: Java effective
-
Effective Java读书笔试之创建和销毁对象 博客分类: effective java effectivejava
-
《effective java》之六:方法 博客分类: Java effective
-
《effective java》之九:并发 博客分类: Java effective
-
《程序员 Java天下事,2010.01 低碳时代之Java风云》8卜被退稿 博客分类: Java JavaJVMSpring编程算法
-
停止启用了安全性的WAS Server而不手动输入密码之第二种选择 博客分类: Java SOAPWebsphereIBMPHPBBS
-
WAS证书过期替换之独立WAS Server之文字操作版 博客分类: Java IBM配置管理应用服务器脚本
-
线程同步之wait() 博客分类: java并发 javathread
-
线程同步之wait() 博客分类: java并发 javathread