java序列化

Java序列化Serialize

序列化與反序列化

序列化:把對象寫入到流中java

反序列化:把對象從流中讀取出來數據庫

什麼狀況下序列化

  1. 對象須要經過網絡進行傳輸
  2. 須要持久化對象到磁盤
  3. 須要持久化對象到數據庫(把對象經過字節流的方式存儲)

序列化的實現方式

實現Serializable接口

  • Serializable是一個標記接口,接口中沒有任何方法
  • 須要序列化的對象除基本數據類型屬性外其餘屬性也必須實現Serializable接口
public class Student implements Serializable{

	private static final long serialVersionUID = 2992794326818594180L;
	
	private String name;
	private int age;
	//省略constructor、setter、getter、toString
}

@Test
public void test1() throws Exception {
  Student s1=new Student("tom",20);
  System.out.println(s1);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s1);

  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
}
輸出:
Student [name=tom, age=20]
Student [name=tom, age=20]

若是序列化對象的非基本數據類型屬性沒有實現Serialize接口,會拋出NotSerializableException異常網絡

public class Student implements Serializable{

	private static final long serialVersionUID = 2992794326818594180L;
	
	private String name;
	private int age;
	private School school;
	//省略constructor、setter、getter、toString
}
class School{
	private String name;
	//省略constructor、setter、getter、toString
}

public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
  Student s1=new Student("tom",20,new School("xw"));
  System.out.println(s1);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s1);

  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
}

輸出:
java.io.NotSerializableException: com.moyuduo.analyze.School

實現Externaliable接口並實現方法

  • 序列化對象的非基本數據類型外其餘類型必須實現Serializable接口或Externaliable接口
  • 實現Externaliable的類必須提供無參構造器,由於在反序列化的時候須要使用無參構造器建立對象

這種方式比實現Serializable接口略複雜,可是能夠實現更加複雜的控制,由於實現Externaliable接口重寫方法須要咱們本身指定序列化規則(能夠對序列化進行加密產生字節)和反序列化規則(序列化規則的逆過程)ide

實現Externaliable接口方式比實現Serializable接口方式的效率高ui

public class Student implements Externalizable{


  private String name;
  private int age;
  private School school;

  public Student() {//必須加無參構造器
    System.out.println("Student無參構造器");
  }
  //省略有參constructor、setter、getter、toString
  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(new StringBuffer(this.name).reverse().toString());
    out.writeInt(this.age);
    out.writeObject(this.school);
  }
  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.name=new StringBuffer((String)in.readObject()).reverse().toString();
    this.age=in.readInt();
    this.school=(School)in.readObject();
  }



}
class School implements Externalizable{
  private String name;
  public School() {
    System.out.println("School無參構造器");
  }
  //省略有參constructor、setter、getter、toString

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(new StringBuffer(this.name).reverse().toString());
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.name=new StringBuffer((String)in.readObject()).reverse().toString();
  }


}

public static void main(String[] args) throws Exception {
  Student s1=new Student("tom",20,new School("xh"));
  System.out.println(s1);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s1);
  oos.close();

  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
  ois.close();
}

輸出:
Student [name=tom, age=20, school=School [name=xh]]
Student無參構造器
School無參構造器
Student [name=tom, age=20, school=School [name=xh]]

部分屬性序列化

使用transient關鍵字

被transient關鍵字修飾的屬性,在對象序列化時不會序列化,並且反序列化獲得的該屬性值是默認值this

public class Student implements Serializable{
  private static final long serialVersionUID = 1L;

  private String name;
  private transient int age;
  //省略constructor、setter、getter、toString
}
public static void main(String[] args) throws Exception{
  Student s=new Student("tom",20);
  System.out.println(s);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s);
  oos.close();

  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
  ois.close();
}
輸出:
Student [name=tom, age=20]
Student [name=tom, age=0]

自定義屬性序列化

  • 能夠實現Externalizable接口並在序列化方法writeExternal中序列化須要的屬性
  • 能夠實現Serializable接口,並本身定義
private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;

writeObject方法序列化須要的屬性加密

public class Student implements Serializable{
  private static final long serialVersionUID = 1L;

  private String name;
  private int age;
  //省略constructor、setter、getter、toString
  private void writeObject(ObjectOutputStream out) throws IOException{
    out.writeObject(this.name);
  }
  private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
    this.name=(String)in.readObject();
  }
}

public static void main(String[] args) throws Exception{
  Student s=new Student("tom",20);
  System.out.println(s);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s);
  oos.close();

  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
  ois.close();
}
輸出:
Student [name=tom, age=20]
Student [name=tom, age=0]

序列化對象的static屬性

在對象進行序列化時,被static修飾的屬性並不會進行序列化code

public class Student implements Serializable{
  private static final long serialVersionUID = 1L;

  private String name;
  public static int age;
  //省略constructor、setter、getter、toString
}

public static void main(String[] args) throws Exception{
  Student s=new Student("tom");
  Student.age=20;
  System.out.println(s);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s);
  oos.close();

  Student.age=30;
  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
  ois.close();
}
輸出:
Student [name=tom,age=20]
Student [name=tom,age=30]

能夠看到Student的static屬性age並無被序列化輸出對象

實現Serializable的類須要提供一個serialVersionUID

serialVersionUID是用於肯定版本信息的,若是不指定JVM會根據類信息自動生成一個,JVM會根據兩個serialVersionUID判斷是不是同一個類,若是serialVersionUID不一致,會拋出InvalidClassException異常接口

通常建議顯式指定serialVersionUID,若是類中添加了新的屬性,而想進行向下兼容的話,能夠不改變serialVersionUID,那麼反序列化後新添加的屬性就是默認值

若是刪除了類的屬性,就須要修改serialVersionUID

public class Student implements Serializable{
  private static final long serialVersionUID = 1L;

  private String name;
  private int age;
  //省略constructor、setter、getter、toString
}

//把對象寫出去
@Test
public void test4() throws IOException {
  Student s=new Student("tom",20);
  System.out.println(s);
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
  oos.writeObject(s);
  oos.close();
}

//刪除Student的age屬性,並修改serialVersionUID
public class Student implements Serializable{
  private static final long serialVersionUID = 2L;

  private String name;
  //省略constructor、setter、getter、toString
}

//讀取對象
public static void main(String[] args) throws Exception{
  Student s=new Student("tom");
  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
  Student s2=(Student)ois.readObject();
  System.out.println(s2);
  ois.close();
}
輸出:
Exception in thread "main" java.io.InvalidClassException: com.moyuduo.analyze.Student; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
相關文章
相關標籤/搜索