java對象的序列化與反序列化


Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據 、對象的類型 和 對象中存儲的屬性 等信息。字節序列寫出到文件之后,相當於文件中持久保存了一個對象的信息。

反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化。 對象的數據 、對象的類型和對象中存儲的數據 信息,都可以用來在內存中創建對象。看圖理解序列化:

 一、ObjectOutputStream

java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到文件,實現對象的持久存儲。

構造方法

public ObjectOutputStream(OutputStream out) : 創建一個指定OutputStream的ObjectOutputStream。

構造舉例,代碼如下:

FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

序列化操作

一個對象要想序列化,必須滿足兩個條件:

1)、該類必須實現 java.io.Serializable 接口, Serializable 是一個標記接口,不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出 NotSerializableException 。
2)、該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態的,使用@transient 關鍵字修飾。

public class Employee implements java.io.Serializable {
    public String name;
    public String address;
    public transient int age; // transient瞬態修飾成員,不會被序列化
    public void addressCheck() {
       System.out.println("Address  check : " + name + " ‐‐ " + address);  
    }
}

不實現serializable會報錯。

寫出對象方法

public final void writeObject (Object obj) : 將指定的對象寫出。

示例

public class SerializeDemo{
   public static void main(String [] args)   { 
     Employee e new Employee();    
     e.name "zhangsan";    
     e.address "beiqinglu";    
     e.age 20;     
     try {    
       // 創建序列化流對象      
          ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
         // 寫出對象    
         out.writeObject(e);    
         // 釋放資源    
         out.close();    
         fileOut.close();    
         System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年齡沒有被序列化
   
        } catch(IOException i)   {
            i.printStackTrace();
        }
   } 
}

二、ObjectInputStream

ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復為對象。

構造方法

public ObjectInputStream(InputStream in) : 創建一個指定InputStream的ObjectInputStream。

反序列化操作1

如果能找到一個對象的class文件,我們可以進行反序列化操作,調用 ObjectInputStream 讀取對象的方法:

public final Object readObject () : 讀取一個對象。

示例

public class DeserializeDemo {
    public static void main(String [] args)   {
        Employee e null;
        try {      
             // 創建反序列化流
             FileInputStream fileIn = new FileInputStream("employee.txt");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             // 讀取一個對象
             e = (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("Name: " + e.name); // zhangsan  
        System.out.println("Address: " + e.address); // beiqinglu
        System.out.println("age: " + e.age); // 0
    }
}

對於JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個ClassNotFoundException 異常

反序列化操作2

另外,當JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發生了修改,那么反序列化操作也會失敗,拋出一個 InvalidClassException 異常。發生這個異常的原因如下:

1)、該類的序列版本號與從流中讀取的類描述符的版本號不匹配
2)、該類包含未知數據類型
3)、該類沒有可訪問的無參數構造方法

Serializable 接口給需要序列化的類,提供了一個序列版本號。 serialVersionUID 該版本號的目的在於驗證序列化的對象和對應類是否版本匹配。

public class Employee implements java.io.Serializable {
     // 加入序列版本號
     private static final long serialVersionUID = 1L;
     public String name;
     public String address;
     // 添加新的屬性 ,重新編譯, 可以反序列化,該屬性賦為默認值.
     public int eid;
     public void addressCheck() {
         System.out.println("Address  check : " + name + " ‐‐ " + address);
     }
}

三、序列化集合

1. 將存有多個自定義對象的集合序列化操作,保存到 list.txt 文件中。
2. 反序列化 list.txt ,並遍歷集合,打印對象信息。

案例分析
1. 把若干學生對象 ,保存到集合中。
2. 把集合序列化。
3. 反序列化讀取時,只需要讀取一次,轉換為集合類型。
4. 遍歷集合,可以打印所有的學生信息

案例實現

public class SerTest {
    public static void main(String[] args) throws Exception {    
    // 創建 學生對象        
    Student student = new Student("老王""laow");        
    Student student2 new Student("老張""laoz");        
    Student student3 new Student("老李""laol");        
    ArrayList<Student> arrayList = new ArrayList<>();        
    arrayList.add(student);        
    arrayList.add(student2);        
    arrayList.add(student3);        
    // 序列化操作        
    // serializ(arrayList);        
           
    // 反序列化          
    ObjectInputStream ois  = new ObjectInputStream(new FileInputStream("list.txt"));        
    // 讀取對象,強轉為ArrayList類型        
    ArrayList<Student> list  = (ArrayList<Student>)ois.readObject();        
           
           for (int i = 0; i < list.size(); i++ ){  
               Student s = list.get(i);  
             System.out.println(s.getName()+"‐‐"+ s.getPwd());
           }  
    }    
    private static void serializ(ArrayList<Student> arrayList) throws Exception {    
    // 創建 序列化流         
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));        
    // 寫出對象        
    oos.writeObject(arrayList);        
    // 釋放資源        
    oos.close();        
    }    
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM