import java.io.*; import java.time.LocalDate; public class Test { public static void main(String[] args){ SerialCloneTest.test(); } } /* 2.4 对象输入/输出流与序列化 2.4.1 保存和加载序列化对象 保存这样的对象网络是一种挑战,在这里我们当然不能去保存和恢复秘书对象的内存地址,因为当对象 被重新加载时,它可能占用的是与原来完全不同的内存地址。与此不同的是,每个对象都是用一个序列 号保存的,这就是这种机制之所以称为对象序列化的原因。下面是其算法: 1.对你遇到的每一个对象引用都关联一个序列号 2.对于每个对象,当第一次遇到时,保存其对象数据到输出流中 3.如果某个对象之前已经被保存过了,那么只写出“与之前保存过的序列好为x的对象相同”。 ============================== = = = serial number = 1 = = type = Employee = = name = "Cat" = = = ============================== = = = serial number = 2 = = type = Manager = = name = "Dog1" = = secretary = object 1 = = = ============================== = = = serial number = 2 = = type = Manager = = name = "Dog2" = = secretary = object 1 = = = ============================== 当读回对象时,算法为: 1.对于对象输入流中的对象,在第一次遇到其序号时,构建它,并使用流中数据来初始化 它,然后记录这个顺序号和新对象之间的关联。 2.当遇到“与之前保存过的序列号为x的对象相同”标记时,获取与这个顺序好相关联的对 象引用。 2.4.2 理解对象序列化的文件格式 2.4.5 版本管理 ——这一部分我没有读,感觉应该会有点意思。 2.4.4 序列化单例和类型安全的枚举 在Java的enum类型之前,有一种写法,我觉得这种写法有利于我理解enum: */ class Orientation{ public static final Orientation HORIZONTAL = new Orientation(1); public static final Orientation VERTICAL = new Orientation(2); private int value; private Orientation(int value) { this.value=value; } } /* 当类型安全的枚举实现Serializable接口时,默认的序列化机制并不可用,你将一个对象写 进流里,再从流里读出来时,序列化机制会重建新的对象。为了解决这个问题,需要定义另一 种称为readResolve的特殊序列化方法。如果定义了readResolve方法,在对象序列化之后 调用它,它必须返回一个对象,而该对象之后会成为readObject的返回值。 */ class ReadResolveTest{ //这段代码各种问题,先做一个标记吧 /* protected Object readResolve() throws ObjectStreamException{ if(value == 1) return Orientation.HORIZONTAL; if(value == 2) return Orientation.VERTICAL; throw new ObjectStreamException(); } */ } /* 2.4.6 为克隆使用序列化 思路: 直接将对象序列化到输出流中,然后将器读回。这样产生的新对象是现有对象 的一个深拷贝。这个方法尽管灵巧,但是会比显式地构建对象并复制或克隆数 据域的克隆方法慢多了。 */ class SerialCloneable implements Cloneable,Serializable{ public Object clone() throws CloneNotSupportedException { try{ ByteArrayOutputStream bout = new ByteArrayOutputStream(); try(ObjectOutputStream out = new ObjectOutputStream(bout)){ out.writeObject(this); } try(InputStream bin = new ByteArrayInputStream(bout.toByteArray())){ ObjectInputStream in = new ObjectInputStream(bin); return in.readObject(); } } catch (IOException | ClassNotFoundException e) { CloneNotSupportedException e2 = new CloneNotSupportedException(); e2.initCause(e); throw e2; } } } class Employee extends SerialCloneable{ private String name; private double salary; private LocalDate hireDay; public Employee(String name, double salary, LocalDate hireDay) { this.name = name; this.salary = salary; this.hireDay = hireDay; } public String getName() { return name; } public double getSalary() { return salary; } public LocalDate getHireDay() { return hireDay; } public void raiseSalary(double byPercent){ double raise = salary * byPercent/100; salary += raise; } @Override public String toString() { return getClass().getName()+"{" + "name='" + name + '\'' + ", salary=" + salary + ", hireDay=" + hireDay + '}'; } } class SerialCloneTest{ public static void test(){ Employee harry = new Employee("Harry Hacker",35000,LocalDate.now()); try { Employee harry2 = (Employee)harry.clone(); harry.raiseSalary(10); System.out.println(harry); System.out.println(harry2); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
《Java核心技术卷二》笔记