欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《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