`

《effective java》之十:序列化

    博客分类:
  • Java
阅读更多

第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第三版1

    《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,它提供了许多最佳实践和设计原则,帮助开发者写出更高效、更可维护的代码。第三版延续了这一传统,对Java语言的新特性进行了更新,并给出了...

    Effective Java.zip

    - 序列化:解释了Java对象如何被序列化和反序列化,以及序列化接口的作用。 - 自定义序列化:讨论了如何通过实现`writeObject()`和`readObject()`方法来自定义序列化行为。 - 隐式序列化风险:提到了序列化可能...

    《Effective Java》读书分享.pptx

    其他知识点还包括泛型、枚举和注解、Lambda 和 Stream、方法、通用编程、异常、并发、序列化等。这些知识点都是 Java 编程语言的核心内容,了解和掌握这些知识点对于编写高质量的 Java 代码至关重要。 《Effective ...

    Effective-Java:Effective Java中文版第二版示例代码

    《Effective Java》是Java开发领域的经典著作,由Joshua Bloch撰写,中文版第二版更是深受广大Java开发者喜爱。...同时,书中还涵盖了其他很多话题,如序列化、注解、反射等,都是Java开发者不可或缺的知识。

    Java-Effective:Java Effective 2nd Edition书中的源代码

    《Effective Java》是Java开发领域的经典著作,由Joshua Bloch撰写,第二版更是程序员们不可或缺的参考书籍。这本书深入探讨了如何编写出高质量、高效、可维护的Java代码,涵盖了众多最佳实践和设计模式。这里我们将...

    Effective-Java-2nd-Edition-(May-2008).zip_effective java

    13. **序列化**:解释了Java序列化的工作原理,以及如何控制序列化行为,包括实现Serializable接口和使用transient关键字。 14. **预优化的陷阱**:告诫开发者不要过早优化代码,大多数情况下,Java的默认性能已经...

    effectiveJava的笔记

    4. **枚举**:介绍枚举类型的强大之处,如枚举的自动序列化、枚举常量之间的比较以及它们可以拥有方法和字段,优于传统的`int`常量。 5. **泛型**:讲解泛型的基本用法,包括类型擦除、边界通配符、类型推断,以及...

    EffectiveJava:有效的 Java 示例

    《EffectiveJava》是Java开发领域的经典著作,由Joshua Bloch撰写,提供了许多关于如何编写高效、可维护和设计良好的Java代码的实用建议。这本书的第2版在原有的基础上进行了更新,以适应Java语言的新发展。现在,...

    1_Effective_Java_2nd_Edition_proglib_java_Joshua_

    9. **序列化**:针对Java的序列化机制, Bloch提出了一些注意事项,如实现Serializable接口的潜在风险,以及如何使用transient和serialVersionUID来控制序列化行为。 10. **最后但同样重要的是,持续学习和改进**:...

    Effective-Java读书笔记

    13. **使用可序列化接口谨慎**:实现Serializable接口使得对象能够被序列化,但也增加了安全风险和版本控制的复杂性。 14. **使用finally块来确保资源的释放**:无论try-catch块的结果如何,finally块中的代码总会...

    effective_java_new:Effective_java_new

    以上只是《Effective Java》中的一部分重要概念,实际书籍中还涉及了很多其他主题,包括集合、多线程、序列化、类设计等方面的最佳实践。通过对这些原则的深入理解和应用,Java开发者可以提升代码质量,编写出更专业...

    Effective.Java_Java8_并发_java_effectivejava_

    目录:一、创建和销毁对象 (1 ~ 7)二、对于所有对象都通用的方法 (8 ~ 12)三、类和接口 (13 ~ 22)四、泛型 (23 ~ 29)五、枚举和注解 (30 ~ 37)六、方法 ...65)九、并发 (66 ~ 73)十、序列化 (74 ~ 78)

    effective-java:Intellij IDEA 的有效 Java 模式重构

    1. **单例模式(Singleton)**:书中推荐使用枚举类型来实现单例,因为枚举天生线程安全且防止了反射和序列化带来的问题。在IntelliJ IDEA中,可以通过"Refactor" -&gt; "Convert to Singleton using Enum"快速转换。 ...

    java源码总结-Effective-Java-3E:有效Java第三版的源代码示例和摘要的回购

    以上只是《Effective Java》第三版中部分核心知识点的概述,实际上,书中还包括了更多关于类型系统、序列化、方法设计、类设计等方面的内容。通过阅读源代码和摘要,开发者可以深入理解这些原则,并将其应用于实际...

    java学习PDF下载地址全 百度云盘下载

    7. **IO流**:讲解输入/输出流的概念,包括文件操作、对象序列化、网络通信等,是处理数据传输的关键技术。 8. **多线程**:讨论并发编程,如何创建和管理线程,以及同步机制如synchronized关键字和wait/notify机制...

    java逻辑思维笔试题-effective-java-3rd-edition:有效的Java第3版注释

    序列化 第 2 章 - 创建和销毁对象 第 1 项 - 考虑静态工厂方法而不是构造函数 传统与灵活的对象实例化方式 静态工厂方法示例: public static Boolean valueOf( boolean b) { return b ? Boolean . TRUE : Boolean ....

    实践《Effective Java》书中的经验法则示例代码,结合Java源码来理解这些最佳实践,并应用于实际项目。.zip

    8. **编写可序列化的类时,应指定`serialVersionUID`(Item 70)**:这可以确保序列化版本的兼容性,避免在反序列化时出现问题。 9. **尽可能使用`Objects.requireNonNull()`方法检查参数(Item 35)**:这个方法能...

    Effective-Java读书笔记(上)

    ### Effective Java读书笔记(上) #### 第一章 引言 本书主要针对Java开发者提供了大量实用的编程指导建议,帮助读者提升代码质量和程序性能。在本章节中,我们将重点介绍对象的创建与销毁,以及一些重要的设计...

Global site tag (gtag.js) - Google Analytics