java中序列化与反序列化_Java中的序列化
java中序列化與反序列化
Java提供了一種稱為序列化的機制,以按字節的有序或字節序列的形式持久化Java對象,其中包括對象的數據以及有關對象的類型和存儲在對象中的數據類型的信息。 因此,如果我們已序列化了任何對象,則可以使用對象的類型和其他信息對其進行讀取和反序列化,以便檢索原始對象。
類ObjectInputStream和ObjectOutputStream是高級流,其中包含用于序列化和反序列化對象的方法。 ObjectOutputStream有許多用于序列化對象的方法,但是常用的方法是:
同樣,ObjectInputStream具有
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException{}需要序列化嗎?
通常在需要通過網絡發送數據或存儲在文件中時使用序列化。 數據是對象,而不是文本。 現在的問題是您的網絡基礎結構和硬盤是可以理解位和字節但不能理解Java對象的硬件組件。 序列化是將Java對象的值/狀態轉換為字節,以便通過網絡發送或保存它。反序列化是將字節碼轉換為相應的Java對象。
serialVersionUID的概念:
SerialVersionUID用于確保在反序列化期間加載相同的對象(在序列化期間使用的對象)。serialVersionUID用于對象的版本控制。您可以在java序列化中的serialVersionUID上內容
對于序列化:
步驟如下:
讓我們舉個例子:在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接口(即標記接口)。
Java中的標記接口是沒有字段或方法的接口,或者簡單的單詞空接口在Java中稱為標記接口。 在src-> org.arpit.javapostsforlearning中創建SerializeMain.java
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因此,我們先序列化了一個雇員對象,然后對其進行反序列化。這看起來很簡單,但是當引用對象,繼承關系出現時,它可能會非常復雜。因此,我們將逐一介紹不同的情況以及如何在不同的情況下應用序列化。
情況1-如果一個對象引用了其他對象怎么辦
我們已經看到了非常簡單的序列化案例,現在如果它也引用了其他對象又該怎么辦呢?它將如何序列化呢? 是的,您不必顯式地序列化引用對象。當序列化任何對象并且如果它包含任何其他對象引用時,Java序列化將序列化該對象的整個對象圖。
例如:讓我們說,Employee現在引用了地址對象,而Address可以引用了其他某個對象(例如Home),那么當您序列化Employee對象時,所有其他引用對象(例如address和home)都將自動序列化。 讓我們創建Address類并添加Address對象作為對上述雇員類的引用。
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:
地址.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.javaposts學習中創建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);//Serializetry{FileOutputStream fileOut = new FileOutputStream('employee.ser');ObjectOutputStream outStream = new ObjectOutputStream(fileOut);outStream.writeObject(emp);outStream.close();fileOut.close();}catch(IOException i){i.printStackTrace();}//Deserializeemp = 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.Addressat 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類也必須是可序列化的。因此,您必須通過實現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類)該怎么辦?
如果您沒有訪問地址類的權限,那么如何在地址類中實現可序列化的接口呢? 是的,您可以創建另一個擴展地址并使其可序列化的類,但是在許多情況下它可能會失敗:
- 如果將類聲明為final怎么辦
- 如果類引用其他不可序列化的對象該怎么辦。
那么,您將如何序列化Employee對象? 所以解決方案是您可以使其瞬態。如果您不想序列化任何字段,請使其瞬態。
transient Address address因此,在運行程序時在Employee類中使地址瞬態之后,您將獲得nullPointerException,因為在反序列化期間地址引用將為null
情況3:如果您仍要保存引用對象的狀態(例如,地址對象上方),該怎么辦:
如果您使地址處于瞬態狀態,那么在反序列化期間它將返回null。但是如果您仍然希望與序列化地址對象時的狀態相同,那么Java序列化提供了一種機制,如果您具有帶有特定簽名的私有方法,則它們將獲得在序列化和反序列化過程中被調用,因此我們將覆蓋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:
地址.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.javaposts學習中創建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);//Serializetry{FileOutputStream fileOut = new FileOutputStream('employee.ser');ObjectOutputStream outStream = new ObjectOutputStream(fileOut);outStream.writeObject(emp);outStream.close();fileOut.close();}catch(IOException i){i.printStackTrace();}//Deserializeemp = 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所以現在我們得到的地址對象的狀態與序列化之前的狀態相同。
序列化中的繼承:
現在我們將了解繼承如何影響序列化,因此在某些情況下,超類是否可序列化是可能的,如果不是,那么您將如何處理它以及它如何工作。 我們將創建Person.java,它將是Employee的超類:
情況4:如果超類是可序列化的怎么辦?
如果超類是可序列化的,則其所有子類都可以自動序列化。
情況5:如果超類不可序列化怎么辦?
如果超類不能序列化,那么我們必須以完全不同的方式處理它。
- 如果超類不可序列化,則它必須沒有參數構造函數。
人.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.javaposts學習中創建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) {//SerializeEmployee 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();}//DeserializeSystem.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時,將獲得以下輸出:
如果超類不可序列化,則在反序列化過程中,將通過調用Non-Serializable超類的構造函數來初始化從超類繼承的實例變量的所有值。 因此,這里name是從person繼承的,因此在反序列化期間,name會初始化為默認值。
情況6-如果超類可序列化但您不希望子類可序列化怎么辦
如果您不希望子類可序列化,則需要實現writeObject()和readObject()方法,并且需要從該方法中拋出NotSerializableException。
情況7-您可以序列化靜態變量嗎?
不,您不能這樣做。您知道靜態變量是在類級別而不是對象級別,并且您序列化了一個對象,因此您無法序列化靜態變量。
摘要:
- 序列化是將Java對象的值/狀態轉換為字節,以便通過網絡發送或保存它。反序列化是將字節碼轉換為相應的Java對象。
- 關于序列化的好處是,整個過程是與JVM無關的,這意味著可以在一個平臺上序列化對象,并在完全不同的平臺上反序列化對象。\
- 如果要序列化任何類,則它必須實現Serializable接口,該接口是標記接口。
- Java中的標記接口是沒有字段或方法的接口,或者簡單的單詞空接口在Java中稱為標記接口
- serialVersionUID用于確保在反序列化期間加載相同的對象(在序列化過程中使用的對象)。serialVersionUID用于對象的版本控制。
- 當序列化任何對象并且如果它包含任何其他對象引用時,Java序列化將序列化該對象的整個對象圖。
- 如果您不想序列化任何字段,請使其為臨時字段。
- 如果超類是可序列化的,則其子類將自動可序列化。
- 如果超類不可序列化,則在反序列化過程中,將通過調用Non-Serializable超類的構造函數來初始化從超類繼承的實例變量的所有值。
- 如果您不希望子類可序列化,則需要實現writeObject()和readObject()方法,并且需要從該方法中拋出NotSerializableException。
- 您不能序列化靜態變量。
參考:來自JCG合作伙伴 Arpit Mandliya的Java 序列化, 適用于初學者博客的Java框架和設計模式 。
翻譯自: https://www.javacodegeeks.com/2013/03/serialization-in-java.html
java中序列化與反序列化
總結
以上是生活随笔為你收集整理的java中序列化与反序列化_Java中的序列化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 声母韵母整体认读音节字母表 声母表韵母表
- 下一篇: 虚势是什么梗 虚势的意思