序列化是什么:
序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得。
序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。
序列化有什么特点:
如果某个类能够被序列化,其子类也可以被序列化。声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态, transient代表对象的临时数据。
什么时候使用序列化:
一:对象序列化可以实现分布式对象。主要应用例如:RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
二:对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的"深复制",即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
1.Serializable方法
package cn.entity;
import java.io.Serializable;
public class Man implements Serializable {
//serialization 的key,相同的Key可以相互序列化和反序列化
private static final long serialVersionUID = 1L;
private String username;
private String password;
public Man(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.entity;
import java.io.Serializable;
public class Person implements Serializable {
//serialization 的key,相同的Key可以相互序列化和反序列化
private static final long serialVersionUID = 1L;
private Man man;
private String username;
private transient int age; //用transient关键字标记的成员变量不参与序列化过程。
public Person() {
System.out.println("person constru");
}
public Person(Man man, String username, int age) {
this.man = man;
this.username = username;
this.age = age;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.Externalizable用法
package cn.entity;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
public class User implements Externalizable {
private String user;
private int age;
public String getUser() {
return user;
}
public int getAge() {
return age;
}
public User() {
System.out.println("user constructor.");
}
public User(String user, int age) {
System.out.println("user constructor two.");
this.user = user;
this.age = age;
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("read external.");
user = (String) in.readObject();
age = in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("write external.");
out.writeObject(user);
out.writeInt(age);
}
}
3.测试
package cn.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.junit.Test;
import cn.entity.Man;
import cn.entity.Person;
import cn.entity.User;
public class ManTest {
//序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得。
@Test
// Serializable:把对象序列化
public void writeSerializableObject() {
try {
Man man = new Man("huhx", "123456");
Person person = new Person(man, "刘力", 21);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:/output.txt"));
objectOutputStream.writeObject("string");
objectOutputStream.writeObject(person);
objectOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
// Serializable:反序列化对象
public void readSerializableObject() {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("F:/output.txt"));
String string = (String) objectInputStream.readObject();
Person person = (Person) objectInputStream.readObject();
objectInputStream.close();
System.out.println(string + ", age: " + person.getAge() + ", man username: " + person.getMan().getUsername());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//在Person类中包含Man的引用,当Person被序列化的时候,从结果可以知道Man也被序列化了
//writeObject方法可以传入String,是因为String首先是一个类,其次它也是实现了Serializable接口的
//Person类中的age字段是transient(英文:暂态),从打印结果可以看到,序列化Person person = new Person(man, "刘力", 21)对象时,age没有进行序列化。如果transient修饰的Object类型的,那么打印的结果将会是null
@Test
// Externalizable的序列化对象
public void writeExternalizableObject() {
User user = new User("huhx", 22);
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:/Externalizable.txt"));
objectOutputStream.writeObject(user);
objectOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
// Externalizable的反序列化对象
public void readExternalizableObject() {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("F:/Externalizable.txt"));
User user = (User) objectInputStream.readObject();
objectInputStream.close();
System.out.println("name: " + user.getUser() + ", age: " + user.getAge());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1、Serializable序列化时不会调用默认的构造器,而Externalizable序列化时会调用默认构造器的!!!
2、Serializable:一个对象想要被序列化,那么它的类就要实现 此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。
Externalizable:他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性。
注意:
对象的序列化并不属于新的Reader和Writer层次结构的一部分,而是沿用老式的InputStream和OutputStream结构,在某些情况下,不得不混合使用两种类型的层次结构。
恢复了一个反序列化的对象后,如果想对其做更多的事情(对象.getClass().xxx),必须保证JVM能在本地类路径或者因特网的其他什么地方找到相关的.class文件。
恢复对象的默认构建器必须是public的,否则会抛异常。
由于Externalizable对象默认时不保存对象的任何字段,所以transient关键字只能伴随Serializable使用,虽然Externalizable对象中使用transient关键字也不报错,但不起任何作用。
3、把transient修饰的字段序列化。