标签:row 对象序列化 AC data tran 传输 buffer 变量 setter
对象序列化的目标是将对象保存到磁盘中,或允许网络中直接传输对象。对象序列化机制允许把内存中的对象转换成平台无关的二进制流,从而允许这种二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点,其它程序一旦获得这种二进制流,都可以将这种二进制流恢复为原来的Java对象。
对象的序列化指将一个Java对象写入IO流中,与此对应,对象的反序列化指从IO流中恢复该Java对象。
如果需要让对象支持序列化机制,则必须让它的类是可序列化的。为了让某个类是可序列化的,该类必须实现如下两个接口之一。
一旦某个类实现了Serializable接口,该类的对象就是可序列化的,程序可以通过如下两个步骤来序列化该对象。
public class Person implements Serializable {
private static final long serialVersionUID = 3232557182439996130L;
private String name;
private int age;
public Person(String name, int age) {
System.out.println("有参构造器");
this.name=name;
this.age=age;
}
public static void main(String[] args) {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"))) {
Person per = new Person("sunqiang", 30);
oos.writeObject(per);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt")))
{
Person person = new Person("sun", 500);
Teacher t1 = new Teacher("li", person);
oos.writeObject(t1);
t1.setName("改变姓名");
oos.writeObject(t1);
} catch (IOException ex) {
ex.printStackTrace();
}
两次将t1对象序列化,但在第二次序列化前改变了t1变量的值,因为t1已经被序列化过一次,再次调用writeObject()不会将该对象写入,下面读取对象,可以看到两次读取的对象name属性相同。
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"))) {
Teacher t1 = (Teacher) ois.readObject();
Teacher t2 = (Teacher) ois.readObject();
System.out.println("t1:name:" + t1.getName());
System.out.println("t2:name:" + t2.getName());
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException cnf) {
cnf.printStackTrace();
}
通过在实例变量前使用transient关键字,可以指定Java序列化时无须理会该实例变量。
使用transient修饰的变量被隔离在序列化机制之外,这样导致在反序列化恢复Java对象是无法获取该实例变量的值。Java还提供了一种自定义序列化机制,通过这种机制可以让程序控制如何序列化各实例变量。
有一个Person类:
public class Person implements Serializable {
private static final long serialVersionUID = -4271096500079406727L;
private String name;
private int age;
//省略getter,setter方法
}
为序列化类提供如下方法:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
下面是一个例子
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(new StringBuffer(name).reverse());
out.writeInt(age);
}
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {
this.name=((StringBuffer)in.readObject()).reverse().toString();
this.age=in.readInt();
}
为序列化类提供如下方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
writeReplace由序列化机制调用,只要该方法存在,Java在序列化机制运行保证在序列化某个对象之前,先调用该对象的writeReplace()方法。
private Object writeReplace(){
ArrayList<Object> list=new ArrayList<>();
list.add(name);
list.add(age);
return list;
}
public static void main(String[] args) {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("replace.txt"));
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("replace.txt"))){
Person person=new Person("sun",550);
oos.writeObject(person);
ArrayList list=(ArrayList)ois.readObject();
System.out.println(list);
} catch (Exception ex) {
ex.printStackTrace();
}
}
为序列化类提供如下方法:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
要实现该接口里的两个方法:
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(new StringBuffer(name).reverse());
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = ((StringBuffer) in.readObject()).reverse().toString();
this.age = in.readInt();
}
需要指出的是当使用Externalizable机制反序列化时,程序会先使用public的无参构造器创建实例,然后才执行readExternal()方法进行反序列化,因此实现Externalizable的序列化类必须提供public的无参构造器。
关于对象序列化,还要注意一下几点:
标签:row 对象序列化 AC data tran 传输 buffer 变量 setter
原文地址:https://www.cnblogs.com/sqmax/p/9045376.html