一个Java对象的表示有各种各样的方式,Java本身也提供给了用户一种表示对象的方式,那就是序列化。
换句话说,序列化只是表示对象的一种方式而已。
序列化
:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。
反序列化
:将字节数组重新构造成对象
序列化对象写入文件后,可以从文件中读取并反序列化。
整个过程独立JVM,意味着一个对象可以在一个平台上序列化,并在完全不同的平台上反序列化。
java.io.serializable
接口transient
如果你想知道Java标准类是否可序列化,请检查类的文档。测试很简单,如果类实现java.io.serializable
接口,那么它是可序列化的;否则,它不是。
ObjectOutputStream
类用于序列化一个对象
这里用Person
对象来演示:
Person实体类:
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 6815682549858613204L;
private long id;
private String name;
private transient int age;
private String gender;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Person(long id, String name, int age, String gender) {
super();
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age
+ ", gender=" + gender + "]";
}
}
序列化测试:
将对象序列化存储到文件中
try {
Person p = new Person(1231L, "李如花", 18, "woman");
FileOutputStream fos = new FileOutputStream("/hello.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
ObjectInputStream
类用于序列化一个对象,将对象从文件中反序列化出。
Ps: 当然这个地方需要注意类型转换。
为了演示方便,我们就对上文中已经被序列化的对象反序列化,
反序列化对象测试:
try {
FileInputStream fis = new FileInputStream("/hello.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
Person person = (Person)ois.readObject();
System.out.println(person.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e){
e.printStackTrace();
}
Console控制台:
这是你可能会有疑惑,为什么李如花
的age
是0,而不是18。这个时候就要说说transient
的作用了。
被声明为transient
的属性不会被序列化,所以上文中person
对象在序列化的时候就没有存储age
这个属性,所以在反序列化时age属性值为默认初始值0。
Java序列化机制是通过在运行时判断类的serialVersionUID
来验证版本一致性的。
在进行反序列化,Java虚拟机会把传过来的字节流中的servialVersionUID
和本地相应实体类的servialVersionUID
进行比较,
如果相同就认为是一致的实体类,可以进行反序列化,否则JVM会拒绝对这个实体类进行反序列化并抛出异常。
如果实现 java.io.Serializable
接口的实体类没有显式定义一个名为serialVersionUID
、类型为long的变量时,Java序列化 机制会根据编译的.class文件自动生成一个serialVersionUID
,如果.class
文件没有变化,那么就算编译再多 次,serialVersionUID
也不会变化。
要成功序列化类,必须满足两个条件:
java.io.serializable
接口transient
Serializable
接口时,所有子类都可以被序列化。Serializable
接口,父类没有,父类中的属性不能序列化(不报错,数据丢失),但是在子类中属性仍能正确序列化。参考文章: