"java对象序列化与对象反序列化"深入详解

• 将对象转换为字节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化。 【[color=red]比如内存里面有Person这样一个对象,这个对象已经new出来了,接下来我把这个对象保存到文件里面,因为内存里面的东西一旦java虚拟机关闭了就都没有了,所以保存到文件里面,保存到文件之后,等到下一次java虚拟机再次起来之后,我再把这个Person对象从文件里面读取回来,再加载到内存中。这就是序列化[/color]】
• 将一个对象保存到永久存储设备上称为持久化。
• 一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。


一看到一个类实现了Serializable接口,编译器就知道这个类是可以序列化的。

• 序列化(serialization)是把一个对象的状态写入一个字节流的过程。当你想要把你的程序状态存到一个固定的存储区域例如文件时,它是很管用的。稍后一点时间,你就可以运用序列化过程存储这些对象

[color=red]序列化是将文件存储到比如文件里面,反序列化是将这个对象从文件再加载回内存里面[/color]。

• 假设一个被序列化的对象引用了其他对象,同样,其他对象又引用了更多的对象。这一系列的对象和它们的关系形成了一个顺序图表。在这个对象图表中也有循环引用。也就是说,对象X可以含有一个对象Y的引用,对象Y同样可以包含一个对象X的引用。对象同样可以包含它们自己的引用。对象序列化和反序列化的工具被设计出来并在这一假定条件下运行良好。如果你试图序列化一个对象图表中顶层的对象,所有的其他的引用对象都被循环的定位和序列化。同样,在反序列化过程中,所有的这些对象以及它们的引用都被正确的恢复。

• 当一个对象被序列化时,只保存对象的[color=red]非静态成员变量[/color],不能保存任何的成员方法和静态的成员变量。
• 如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
• 如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为[color=red]transient[/color],那么对象仍然可以序列化。

• Serializable接口
–只有一个实现Serializable接口的对象可以被序列化工具存储和恢复。Serializable接口没有定义任何成员。它只用来表示一个类可以被序列化。如果一个类可以序列化,它的所有子类都可以序列化。
–[color=red]声明成transient的变量不被序列化工具存储。同样,static变量也不被存储[/color]。


• ObjectOutput接口 (序列化里面特别重要的一个接口)
–ObjectOutput 继承DataOutput接口并且支持对象序列化。特别注意writeObject( )方法,它被称为序列化一个对象,把一个对象存放到例如文件里面。所有这些方法在出错情况下引发IOException 异常。

• ObjectOutputStream类
–ObjectOutputStream类继承OutputStream 类和实现ObjectOutput 接口。它负责向流写入对象。该类的构造方法如下:
–ObjectOutputStream(OutputStream outStream) throws IOException
–参数outStream 是序列化的对象将要写入的输出流。


• ObjectInput (序列化里面很重要的接口)
–ObjectInput 接口继承DataInput接口。它支持对象序列化。特别注意 readObject( )方法,它叫反序列化对象,是从文件里面读取出对象。所有这些方法在出错情况下引发IOException 异常。


• ObjectInputStream
–ObjectInputStream 继承InputStream 类并实现ObjectInput 接口。ObjectInputStream 负责从流中读取对象。该类的构造方法如下:
– ObjectInputStream(InputStream inStream) throws IOException,StreamCorruptedException
–参数inStream 是序列化对象将被读取的输入流。


–[color=red]反序列化时不会调用对象的任何构造方法,仅仅根据所保存的对象状态信息,在内存中重新构建对象[/color]。


1. 一个类若想被序列化,则需要实现java.io.Serializable 接口,该接口中没有定义任何
方法,是一个标识性接口(Marker Interface),当一个类实现了该接口,就表示这个
类的对象是可以序列化的。
2. 在序列化时,static变量是无法序列化的;如果A包含了对B的引用,那么在序列化
A的时候也会将B一并地序列化;如果此时A可以序列化,B无法序列化,那么当
序列化A的时候就会发生异常,这时就需要将对B的引用设为transient,该关键字
表示变量不会被序列化【这两个方法定义在需要被序列化的类里面,这部分不是太重要,了解下即可】。
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.writeInt(age);
out.writeUTF(name);
out.writeDouble(height);

System.out.println("write object");
}

private void readObje(java.io.ObjectInputStream in) throws IOException {
age = in.readInt();
name = in.readUTF();
height = in.readDouble();

System.out.println("read object");
}
3. 当我们在一个待序列化/反序列化的类中实现了以上两个private方法(方法声明要
与上面的保持完全的一致),那么就允许我们以更加底层、更加细粒度的方式控制序
列化/反序列化的过程。


• 在序列化和反序列化进程中需要特殊处理的 Serializable 类应该实现以下方法:
• private void writeObject(java.io.ObjectOutputStream stream) throws IOException;

• private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException;
这两个方法不属于任何一个类和任何一个接口,是非常特殊的方法【这两个方法定义在需要被序列化的类里面,这部分不是太重要,了解下即可】.


下面是序列化与反序列化的一个使用示例(重点):
package com.shengshiyuan.serializable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializableTest1 {
public static void main(String[] args) throws Exception {
Person person = new Person(20, "hello", 3.45);
Person person2 = new Person(30, "world", 4.45);
Person person3 = new Person(40, "welcome", 5.45);

FileOutputStream fos = new FileOutputStream("person.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(person);
oos.writeObject(person2);
oos.writeObject(person3);

oos.close();

FileInputStream fis = new FileInputStream("person.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Person resPerson = (Person) ois.readObject();
System.out.println(resPerson.getAge() + "," + resPerson.getName() + ","
+ resPerson.getHeight());
Person resPerson2 = (Person) ois.readObject();
System.out.println(resPerson2.getAge() + "," + resPerson2.getName()
+ "," + resPerson2.getHeight());
Person resPerson3 = (Person) ois.readObject();
System.out.println(resPerson3.getAge() + "," + resPerson3.getName()
+ "," + resPerson3.getHeight());
ois.close();
}
}

class Person implements Serializable {
int age;
transient String name;
double height;

public Person(int age, String name, double height) {
this.age = age;
this.name = name;
this.height = height;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getHeight() {
return height;
}

public void setHeight(double height) {
this.height = height;
}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值