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