程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深刻分析Java編程中的序列化

深刻分析Java編程中的序列化

編輯:關於JAVA

深刻分析Java編程中的序列化。本站提示廣大學習愛好者:(深刻分析Java編程中的序列化)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻分析Java編程中的序列化正文


 Java供給一種機制叫做序列化,經由過程有序的格局或許字節序列耐久化java對象,個中包括對象的數據,還有對象的類型,和保留在對象中的數據類型。

所以,假如我們曾經序列化了一個對象,那末它可以被讀取並經由過程對象的類型和其他信息停止反序列化,並終究獲得對象的原型。

ObjectInputStream 和 ObjectOutputStream對象是高等其余流對象,包括序列化和反序列化的辦法。

ObjectOutputStream 具有許多序列化對象的辦法,最經常使用的是:
 

private void writeObject(ObjectOutputStream os) throws IOException
 {
   
 }

相似的 ObjectInputStream 供給以下辦法:
 

 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
   
 }

那末哪裡會須要序列化呢?序列化平日在須要經由過程收集傳輸數據,或許保留對象到文件的場所應用。這裡說的數據是對象而不是文本。

如今的成績是,我們的收集架構和硬盤都只能辨認二進制和字節,而不克不及辨認Java對象。

序列化就是把Java對象中的value/states翻譯為字節,以便經由過程收集傳輸或許保留。別的,反序列化就是經由過程讀取字節碼,並把它翻譯回java對象。

serialVersionUID概念

serialVersionUID 是用於包管統一個對象(在序列化中會被用到)可以在Deserialization進程中被載入。serialVersionUID 是用於對象的版本掌握。你可以參考serialVersionUID in java serialization獲得更多信息。

關於序列化:

步調以下:

讓我們看一個列子:

在 src->org.arpit.javapostsforlearning 創立Employee.java

1.Employee.java 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
  
 public int getEmployeeId() {
  return employeeId;
 }
 public void setEmployeeId(int employeeId) {
  this.employeeId = employeeId;
 }
 public String getEmployeeName() {
  return employeeName;
 }
 public void setEmployeeName(String employeeName) {
  this.employeeName = employeeName;
 }
 public String getDepartment() {
  return department;
 }
 public void setDepartment(String department) {
  this.department = department;
 }
}

就如你所見的,假如你須要序列化任何類,那末你 必需完成 Serializable 接口 ,這個接口是標志接口(marker interface)。


Java中的標志接口(marker interface)就是一個沒有任何字段或許辦法的接口,簡略的來講,java中把空接口叫做標志接口(marker interface)

2.SerializeMain.java
 

package org.arpit.javapostsforlearning;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 public class SerializeMain {
 
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 }
}

關於反序列化:
步調是

在包src->org.arpit.javapostsforlearning中,創立 DeserializeMain.java
3.DeserializeMain.java
 

package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
 
public class DeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = null;
  try
  {
   FileInputStream fileIn =new FileInputStream("employee.ser");
   ObjectInputStream in = new ObjectInputStream(fileIn);
   emp = (Employee) in.readObject();
   in.close();
   fileIn.close();
  }catch(IOException i)
  {
   i.printStackTrace();
   return;
  }catch(ClassNotFoundException c)
  {
   System.out.println("Employee class not found");
   c.printStackTrace();
   return;
  }
  System.out.println("Deserialized Employee...");
  System.out.println("Emp id: " + emp.getEmployeeId());
  System.out.println("Name: " + emp.getEmployeeName());
  System.out.println("Department: " + emp.getDepartment());
 }
}


4.運轉:
起首運轉SerializeMain.java,然後運轉 DeserializeMain.java,你會獲得以下的成果:
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS

就如許,我們序列化了一個employee對象,並對它停止反序列化。這看起來和簡略,然則假如個中包括對象援用,繼續,那末情形就會變得龐雜。接上去讓我們一個接一個的看一下例子,看看若何在各類場所中完成序列化。

案例1 - 假如對象援用了其他對象,那該若何

我們曾經看過最簡略的序列化例子,如今看看,若何處置對象中援用了其他對象的場所。我們該若何序列化?援用對象也會被序列化嗎?對的,你不須要顯式的序列化援用對象。當你序列化任何對象,假如它包括援用對象,那末Java序列化會主動序列化該對象的全部對象圖。例如,Employee如今援用了一個address對象,而且Address也援用了其他對象(例如,Home),那末當你序列化Employee對象的時刻,一切其他援用對象,例如address和home將會被主動地被序列化。讓我們來創立Address類,並它Address的對象作為援用,添加到employee類中。

Employee.java: 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
}

在 org.arpit.javapostsforlearning 包中,創立Address.java
Address.java: 
 

package org.arpit.javapostsforlearning;
public class Address {
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

在包 org.arpit.javapostsforlearning中,創立SerializeDeserializeMain.java
SerializeDeserializeMain.java:
 

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}

運轉它:
當你運轉SerializeDeserializeMain.java。你會獲得如許的成果:
 

java.io.NotSerializableException: org.arpit.javapostsforlearning.Address
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
 at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
 at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.writeObject(Unknown Source) 

我們將說明哪裡失足了。我忘卻了說,Address 類也必需是serializable。那末Address類必需繼續serialzable接口。

Address.java:
 

import java.io.Serializable;
 
public class Address implements Serializable{
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

再次運轉:
當你再次運轉SerializeDeserializeMain.java。你可以獲得以下的成果
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune

案例2:假如我們不克不及拜訪援用對象的源代碼(例如,你不克不及拜訪下面的Address類的源碼)

假如我們不克不及拜訪到address類,那末我們該若何在Address類中完成serializable 接口?能否有別的的門路來完成呢?對的,你可以創立別的一個類,並繼續Address,然後讓它繼續serializable 接口,然則關於上面的情形,這個計劃會掉敗:

    假如援用類被界說為final
    假如援用類援用了別的一個非可序列化的對象

那末,我們該若何序列化Employee對象?處理的方法是,標志transient。假如你不須要序列化任何字段,只需把它標志為transient。
 
transient Address address
在Employee類中,標志了address為transient以後,運轉法式。你會獲得nullPointerException,由於在反序列化進程中,Address援用將會是null。


案例3 - 假如我依然須要保留援用對象的狀況呢?(例如address對象)

假如你在反序列化進程中,標志了address為transient,它將會前往null成果。然則假如你依然須要保留它的狀況,你就須要序列化address對象。 Java序列化供給一個機制,假如你有特定簽名的private辦法,那末它們就會在序列化和反序列化進程中被挪用,所以我們將重寫Employee類的writeObject和readObject辦法,然後它們就會在Employee對象序列化/反序列化進程中被挪用。

Employee.java:

package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 transient Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
 
 private void writeObject(ObjectOutputStream os) throws IOException, ClassNotFoundException
 {
 try {
 os.defaultWriteObject();
 os.writeInt(address.getHomeNo());
 os.writeObject(address.getStreet());
 os.writeObject(address.getCity());
 }
 catch (Exception e)
 { e.printStackTrace(); }
 }
 
 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
 try {
 is.defaultReadObject();
 int homeNo=is.readInt();
 String street=(String) is.readObject();
 String city=(String) is.readObject();
 address=new Address(homeNo,street,city);
 
 } catch (Exception e) { e.printStackTrace(); }
 }
}

別的有一點須要切記的,ObjectInputStream讀取數據的次序和ObjectOutputStream寫入數據的次序是分歧的.

在包org.arpit.javapostsforlearning 中創立Address.java
Address.java: 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Address {
 
 int homeNo;
 String street;
 String city;
 
 
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

在包org.arpit.javapostsforlearning中創立SerializeDeserializeMain.java
SerializeDeserializeMain.java:
 

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}

運轉 :
當你運轉SerializeDeserializeMain.java.你會獲得以下的成果: 
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune

如今我們就獲得了address對象的狀況,就如它被序列化前的一樣。

序列化中的繼續:

如今我們看看繼續是若何影響序列化的。不論父類是否是可序列化,這將引出許多個例子。假如父類長短可序列化的,我們將若何處置,而且它是若何任務的。讓我們看看例子。

我們將創立一個Person.java,作為 Employee的父類。

案例4: 假如父類是可序列化的

假如父類可序列化,那末一切的繼續類將是可序列化的。

案例5: 假如父類為非可序列化呢?

假如父類為非可序列化的 ,那末我們的處置方法會很紛歧樣。

    假如父類為非可序列化的,那末它必定不會有參數結構函數。

Person.java 
 

package org.arpit.javapostsforlearning;
public class Person {
 
 String name="default";
 String nationality;
 
 public Person()
 {
 System.out.println("Person:Constructor");
 }
 
 public Person(String name, String nationality) {
 super();
 this.name = name;
 this.nationality = nationality;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 public String getNationality() {
 return nationality;
 }
 
 public void setNationality(String nationality) {
 this.nationality = nationality;
 }
 
}

在包org.arpit.javapostsforlearning 中創立Employee.java
Employee.java:

 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee extends Person implements Serializable{
 
 int employeeId;
 String department;
 
 public Employee(int employeeId,String name,String department,String nationality)
 {
 super(name,nationality);
 this.employeeId=employeeId;
 this.department=department;
 System.out.println("Employee:Constructor");
 }
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
}

在org.arpit.javapostsforlearning包中創立SerializeDeserializeMain.java

SerializeDeserializeMain.java:


package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 //Serialize
 Employee emp = new Employee(101,"Arpit","CS","Indian");
 System.out.println("Before serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 System.out.println("************");
 System.out.println("Serializing");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 System.out.println("************");
 System.out.println("Deserializing");
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("After serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 }
}

運轉:

當你運轉SerializeDeserializeMain.java後,你會獲得以下的輸入,假如父類長短可序列化的,那末在反序列化進程中,一切繼續於父類的實例變量值,將會經由過程挪用非序列化結構函數來初始化。 這裡 name繼續於person,所以在反序列化進程中,name將會被初始化為默許值。


案例6 - 假如父類是可序列化,但你不須要繼續類為可序列化

假如你不願望繼續類為可序列化,那末你須要完成 writeObject() 和readObject() 辦法,而且須要拋出NotSerializableException 異常。

案例7 - 能否序列化靜態變量?

不克不及。由於靜態變量是類級其余,不是對象級其余,當你序列化一個對象的時刻,是不克不及序列化靜態變量。


總結:

  •     序列化是java對象的values/states轉化為字節並在收集中傳輸或許保留它的進程。別的反序列化是把字節碼翻譯為對應的對象的進程。
  •     序列化的利益是,JVM的自力性,也就是說,一個對象可以在一個平台中被序列化,然後在別的一個分歧的平台反序列化。
  •     假如你須要序列化任何對象,你必需完成標志接口Serializable。
  •     Java中的標志接口(Marker interface)就是沒有字段或許辦法的接口,或許更簡略的說,空接口
  •     serialVersionUID 是用於包管統一個對象(在序列化中會被用到)可以在Deserialization進程中被載入。serialVersionUID 是用於對象的版本掌握。
  •     當你須要序列化任何包括援用對象的對象,那末Java會主動序列化該對象的全部對象圖。
  •     假如你不願望序列化某個字段,你可以標志它為trasient
  •     假如父類為可序列化,那末它的繼續類也將是可序列化的。
  •     假如父類為非可序列化,那末在反序列化進程中,一切繼續於父類的實例變量值將會經由過程挪用非可序列化的結構器來初始化。
  •     假如你需願望子類為可序列化的,那末你須要完成writeObject() 和 readObject() 辦法,並在這兩個辦法中拋出NotSerializableException異常
  •     你不克不及序列化靜態變量。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved