深刻分析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 - 能否序列化靜態變量?
不克不及。由於靜態變量是類級其余,不是對象級其余,當你序列化一個對象的時刻,是不克不及序列化靜態變量。
總結: