java编程思想阅读笔记(十)I/O系统(下)

补充下对象序列化的相关内容。至于XML读写之类的就不写了,无非也就是按照规定方式读写的东西。
对象的序列化将那些实现了Serializable(Externalizable)接口的对象转换成一个字节序列,并能在以后将这字节序列完全恢复为原来的对象;说得白话些就是将对象相关的信息保存起来(可以写到文件里,或者远程发送出去),在需要的时候把这些保存的信息再恢复出来形成对象;这里就会有下面一些问题:
1.保存了完整的对象信息了吗?
对象的序列化的字节序列中,保存了对象的数据成员(属性),同时也包括了其成员所引用的信息;在恢复过程中不需要调用任何构造器;那么经过远程传输为什么却不可以直接恢复,原因是需要用到起class对象信息,看一下简单的用法:
ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(""));
out.writeObject(duixiang);

ObjectInputStream in = new ObjectInputStream( new FileInputStream(""));
(类型)in.readObject();
这是一个简单的将对象序列化到文件中,然后读取文件再恢复的过程;不难理解如果是不同程序之间对象的恢复,至少得有这个对象的类型信息啊。
2.有些成员不想保存当前信息
对于序列化的控制,可以使用Externalizable接口,通过writeExternal() readExternal()方法来做。这个在序列化时通过将当前信息在writeExterna方法中保存想要保存的信息,恢复时,调用默认的构造器之后,通过readExternal方法将保存的信息恢复出来。这里就看到与实现Serializable接口的区别,一个不需要调用任何的构造器,一个调用默认的构造器。
那么如果想用到Serializable的自动化,又不想保存部分成员信息呢,可以使用transient关键字:
private transient string password;
3.对于引用的分歧
如果序列化多个对象,而都引用了一个对象,那么这个对象在恢复的时候是有不同的副本还是只有一个存储地址?通过下面的例子可以看到:
package com.test.myjava;

//主要演示了Serializable接口以及transient关键字
import java.io.*;
class Information implements Serializable{}
public class SerializableTest implements Serializable{
	private int id;
	private transient String password;
	private String name;
	private Information otherInformation;
	public SerializableTest(int i,String p,String n,Information f){
		System.out.println("Constructor:"+n);
		id = i;
		password = p;
		name = n;
		otherInformation = f;
	}
	public String toString(){
		return "id:"+id +" name:"+name +" pasword:"+password //密码没有保存,为null
		          +" friendName:"+otherInformation;//otherInformation.hashCode() 
	}
	public static void main(String[] args ) throws IOException,ClassNotFoundException{
		Information allFriendName = new Information();

		SerializableTest user1 = new SerializableTest(1,"1","user1",allFriendName);
		SerializableTest user2 = new SerializableTest(2,"2","user2",allFriendName);
		SerializableTest user3 = new SerializableTest(3,"3","user3",allFriendName);
		
		System.out.println("Start\n");
		System.out.println(user1.toString());
		System.out.println(user2.toString());
		System.out.println(user3.toString());
		//序列化
		ByteArrayOutputStream buf1 = new ByteArrayOutputStream();
		ObjectOutputStream out1 = new ObjectOutputStream(buf1);
		out1.writeObject(user1);
		out1.writeObject(user2);
		
		ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
		ObjectOutputStream out2 = new ObjectOutputStream(buf2);
		out2.writeObject(user3);
		//恢复
		ObjectInputStream in1 = new ObjectInputStream(
				new ByteArrayInputStream(buf1.toByteArray()));
		ObjectInputStream in2 = new ObjectInputStream(
				new ByteArrayInputStream(buf2.toByteArray()));
		user1 = (SerializableTest)in1.readObject();
		user2 = (SerializableTest)in1.readObject();
		user3 = (SerializableTest)in2.readObject();
		
		System.out.println("Then\n");
		System.out.println(user1.toString());
		System.out.println(user2.toString());
		System.out.println(user3.toString());

	}
}

输出结果:

Constructor:user1
Constructor:user2
Constructor:user3
Start

id:1 name:user1 pasword:1 friendName:com.test.myjava.Information@c17164
id:2 name:user2 pasword:2 friendName:com.test.myjava.Information@c17164
id:3 name:user3 pasword:3 friendName:com.test.myjava.Information@c17164
Then

id:1 name:user1 pasword:null friendName:com.test.myjava.Information@19b49e6
id:2 name:user2 pasword:null friendName:com.test.myjava.Information@19b49e6
id:3 name:user3 pasword:null friendName:com.test.myjava.Information@10d448

对于写到一个流中的引用,确实都指向一个地址,而对于不同的流则有不同的副本。

你可能感兴趣的:(java编程思想)