readObejct/writeObject在序列化、反序列化,RMI、RPC等场景中应用广泛。
public class IOTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Leaf dog = new Leaf("Kim", "Yellow");
FileOutputStream fileOutputStream = new FileOutputStream("dog.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject("dog\n");
objectOutputStream.writeObject(dog);
objectOutputStream.close();
FileInputStream fileInputStream = new FileInputStream("dog.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
objectInputStream.close();
}
}
public class Leaf implements Serializable {
private String name;
private String color;
private final static Long serialVersionUID = 1L;
public Leaf(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Leaf[");
stringBuilder.append("name:" + this.name + ",");
stringBuilder.append("color:" + this.color + "]");
return stringBuilder.toString();
}
}
结果:
dog
Leaf[name:Kim,color:Yellow]
分析:
结果很简单,但是需注意的是,已经自动调用了Leaf类的toString()方法,而且我们并没有显式的向下转型,查看println()源码,最终调用了对象的toString(),说明这个obj在内存中实际指向的是一个具有Leaf类型的对象,
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
查看readObject方法,发现其会根据读取的字节自动判断是什么类型的东东,比如是String,class等等,而用writeObject写入的对象自带了类名,字段及值信息。进入resolveClass函数后,程序会在已经定义和使用的类加载器加载对应类名的类对象找到对应的类信息,
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String name = desc.getName(); try { return Class.forName(name, false, latestUserDefinedLoader()); } catch (ClassNotFoundException ex) { Class<?> cl = primClasses.get(name); if (cl != null) { return cl; } else { throw ex; } } }
找到类信息后,newIntance创建一个类对象,然后readSerialData->defaultReadFields,填充对象属性字段。
中间的newInstance虽然返回的是object引用,但是按照实际的类进行创建对象的,调用toString的方法则找到了对象实际的类型信息对应的toString()方法。