IO流序列化与反序列化
前言
一、序列化与反序列化是什么?
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
把Java对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为Java对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
二、使用步骤
//玩家类
import java.io.Serializable;
public class Player implements Serializable{
/**
*
*/
private static final long serialVersionUID = 137842784923423L;
private String name;
private transient int level=10;
private int life;
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
private Car car;
public Player(String name, int level, Car car) {
super();
this.name = name;
this.level = level;
this.car = car;
System.out.println("1111111111111111");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public Player(String name, int level) {
super();
this.name = name;
this.level = level;
System.out.println("全参构造器。。。");
}
public Player() {
super();
System.out.println("无参构造器....");
}
@Override
public String toString() {
return "Player [name=" + name + ", level=" + level + ", life=" + life + ", car=" + car + "]";
}
}
class Car implements Serializable{
private String brand;
private int price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Car(String brand, int price) {
super();
this.brand = brand;
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
public class TestPlayer {
public static void main(String[] args) throws ClassNotFoundException {
//对象的序列化s
Player p = new Player("卡卡西",5,new Car("法拉利", 10));
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D://b.txt"));
oos.writeObject(p);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D://b.txt"));
Object object=ois.readObject();
System.out.println(object);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结
transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
一个JAVA对象要想被序列化吗,必须实现 Serializable 接口,表示当前类的
对象可以参与序列化操作,否则在序列化时抛出java.io.NotSerializableException 异常
该接口是一个空接口,没有任何抽象方法的定义,空接口在程序中是用来做 标记的 ,便于在程序执行期间进行检查
序列化的底层代码会在序列化之前通过反射技术读取类的描述信息【有没有实现规定的接口】
注意:在反序列化生成对象时,没有经过类的构造器调用,而是由JVM底层自动生成
两个小细节:
默认情况下在序列化一个对象时,所有的属性全部参与,但是有时我们希望对象的某个敏感属性不参与序列化的过程,可以使用关键字 transient 将该属性修饰为不参与对象序列化的状态
在序列化的时候,不仅保存了对象的属性状态还记录了当前的类的版本号【默认由JVM生成】,当我们修改了一个类的属性状态时这个版本会发生变更,在反序列化时会检查当前的版本号和序列化时记录的版本号是否一致,如果不一致则抛出异常InvalidClassException
如果类的版本的修改对后期的业务来说没有什么影响,我们就不希望抛出这样的异常,可以将类的序列化版本号固定下来