Java序列化技術與Protobuff


前言:

       Java序列化是Java技術體系當中的一個重要議題,序列化的意義在於信息的交換和存儲,通常會和io、持久化、rmi技術有關(eg:一些orm框架會要求持久化的對象類型實現Serializable接口)。

       本文將提供Java自帶序列化機制和ProtoStuff的序列化(僅僅當作一種數據格式)的比較,從序列化的內容和特點來對二者進行比較。

       結論:1,Java序列化對象時不需要通過屬性的get set方法或其它無關序列化內部定義的方法(比如readObject,writeObject是內置的序列化方法),序列化也不需要get set方法支持,反序列化是構造對象的一種手段

               2,Java序列化時類型必須完全匹配(全路徑類名+序列化id)。

               3,Protostuff反序列化時並不要求類型匹配,比如包名、類名甚至是字段名,它僅僅需要序列化類型A 和反序列化類型B 的字段類型可轉換(比如int可以轉換為long)即可

 

java.io.Serializable

       標識一個對象需要系列化,該對象類型需要實現 Serializable 接口。關於序列化的認識,可以參考IBM社區的文章《Java序列化的高級認識》,本文直接拿該文檔的結論。

       1,序列化的類型和反序列化的類型的序列化ID必須一致(遠程信息交換時)。

       2,靜態數據不會被序列化,Transient關鍵字修飾的字段不會被序列化。

       3,對象序列化存儲時,兩次存儲相同值對象會有優化(第二次對象寫入會只存儲引用)。

序列化技術

      序列化的目的是進行數據存儲和交換,依據這個概念,xml,json也是一種序列化的技術,只是他們似乎是一種容易分辨的序列化技術,而類似於protostuff或Java自身的序列化技術似乎略神秘。

      那么,Java序列化技術與其它的序列化技術究竟有什么不同呢?下文將比較Java自身的序列化技術和protostuff做比較,窺探一二。

Protostuff

     官網:https://code.google.com/p/protostuff/

     Protostuff是基於大名鼎鼎的Google protobuff技術的Java版本,直接使用原生的protobuff是需要數據結構的預編譯過程,需要編寫.proto格式的配置文件,再通過protobuf提供的工具翻譯成目標語言代碼,而Protostuff動態支持了protobuff的預編譯的過程。

    

下面的示例代碼用於證明前言提出的結論

     1,用於測試的實體(中括號內代表屬性)

     org.wit.ff.testmodel.SerializableUserA[String name, int age];

     org.wit.ff.testmodel.SerializableUserB[String name, int age];

     org.wit.ff.testmodel.ch.SerializableUserA[String name, int age];

     org.wit.ff.testmodel.ch.SerializableUserC[String noneName, double noneAge];

     org.wit.ff.testmodel.ch1.SerializableUserA[String name, int age, String firstName];

     org.wit.ff.testmodel.ch1.SerializableUserB[String noneName, int noneAge];

     org.wit.ff.testmodel.ch1.SerializableUserC[String noneName, int noneAge];

     2,測試用例:

package org.wit.ff;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.junit.Test;
import org.wit.ff.testmodel.SerializableUserA;
import org.wit.ff.testmodel.SerializableUserB;
import org.wit.ff.util.ProtoStuffSerializerUtil;

/**
 * 
 * <pre>
 * Java原生序列化機制.
 * 與方法無關.
 * 
 * 安全.
 * 
 * </pre>
 *
 * @author F.Fang
 * @version $Id: JavaSerializableDemo.java, v 0.1 2014年10月29日 上午12:48:11 F.Fang Exp $
 */
public class JavaSerializableDemo {

    /**
     * 
     * <pre>
     * Java自帶序列化機制:檢測對象序列化的內容.
     * 序列化與方法無關,屬性的賦值不通過方法.
     * </pre>
     * 
     */
    @Test
    public void test1() {
        SerializableUserA userA = new SerializableUserA("nobody",18);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
        try {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(userA);
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] userABytes = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(userABytes);
        try {
            ObjectInputStream ois = new ObjectInputStream(bais);
            SerializableUserA userAS = (SerializableUserA) ois.readObject();
            //System.out.println(userAS);
            assertEquals(userA,userAS);
        } catch (IOException e) {
            e.printStackTrace();
            assertFalse(true);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            assertFalse(true);
        }
    }

    /**
     * 
     * <pre>
     * Java自帶序列化機制:序列化和反序列化的類不同.
     * (包括包和類名不同)
     * java.lang.ClassCastException.
     * </pre>
     * 
     */
    @Test
    public void test2() {
        SerializableUserA userA = new SerializableUserA("nobody",18);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
        try {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(userA);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] userABytes = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(userABytes);
        try {
            ObjectInputStream ois = new ObjectInputStream(bais);
            org.wit.ff.testmodel.ch.SerializableUserA userA1 = (org.wit.ff.testmodel.ch.SerializableUserA) ois
                            .readObject();
            System.out.println(userA1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch(java.lang.ClassCastException e){
            e.printStackTrace();
            assertTrue(true);
        }
    }
    
    /**
     * 
     * <pre>
     * 使用protobuff執行序列化.
     * </pre>
     *
     */
    @Test
    public void test3(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        SerializableUserA userAs = ProtoStuffSerializerUtil.deserialize(arr, SerializableUserA.class);
        //System.out.println(userAs);
        assertNotNull(userAs);
        assertEquals(userA.getAge(),userAs.getAge());
        assertEquals(userA.getName(),userAs.getName());
    }
    
    /**
     * 
     * <pre>
     * 使用Protobuff進行序列化.
     * 序列化時的類和反序列化的類包路徑不同.
     * 反序列化成功.
     * </pre>
     *
     */
    @Test
    public void test4(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        org.wit.ff.testmodel.ch.SerializableUserA userAs = ProtoStuffSerializerUtil.deserialize(arr, org.wit.ff.testmodel.ch.SerializableUserA.class);
        //System.out.println(userAs);
        assertEquals(18,userAs.getAge());
        assertEquals("nobody",userAs.getName());
    }
    
    /**
     * 
     * <pre>
     * 使用Protobuff進行序列化.
     * 序列化時的類和反序列化的類屬性相同,類名不同.
     * 反序列化成功.
     * </pre>
     *
     */
    @Test
    public void test5(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        SerializableUserB userBs = ProtoStuffSerializerUtil.deserialize(arr, SerializableUserB.class);
        // System.out.println(userBs);
        assertEquals(18,userBs.getAge());
        assertEquals("nobody",userBs.getName());
    }
    
    /**
     * 
     * <pre>
     * 使用Protobuff進行序列化.
     * 序列化時的類的屬性都包含在反序列化的類屬性中.
     * 反序列化成功.
     * </pre>
     *
     */
    @Test
    public void test6(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        org.wit.ff.testmodel.ch1.SerializableUserA userAs = ProtoStuffSerializerUtil.deserialize(arr, org.wit.ff.testmodel.ch1.SerializableUserA.class);
        // System.out.println(userAs);
        assertEquals(18,userAs.getAge());
        assertEquals("nobody",userAs.getName());
    }
    
    /**
     * 
     * <pre>
     * 使用Protobuff進行序列化.
     * 序列化時的類和反序列化的類完全不同,屬性名稱也不相同,類型一致.
     * 反序列化成功.
     * </pre>
     *
     */
    @Test
    public void test7(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        org.wit.ff.testmodel.ch1.SerializableUserB userBs = ProtoStuffSerializerUtil.deserialize(arr, org.wit.ff.testmodel.ch1.SerializableUserB.class);
        System.out.println(userBs);
        assertEquals("nobody",userBs.getNoneName());
        assertEquals(18,userBs.getNoneAge());
    }

    /**
     * 
     * <pre>
     * 使用Protobuff進行序列化.
     * 序列化時的類和反序列化的類完全不同,屬性名稱也不相同.
     * 各屬性類型均不匹配.
     * 針對屬性
     * 如果序列化類型為int 8
     * 反序列化的類型為long
     * 序列化成功.
     * 反序列化的類型為double
     * 反序列化不成功.
     * eg1:
     * SerializableUserA :age int,name String
     * SerializableUserC : noneAge double, noneName String
     * 反序列化不成功.
     * SerializableUserC : noneAge long, noneName String
     * 反序列化成功.
     * </pre>
     *
     */
    @Test
    public void test8(){
        SerializableUserA userA = new SerializableUserA("nobody",18);
        byte[] arr = ProtoStuffSerializerUtil.serialize(userA);
        org.wit.ff.testmodel.ch1.SerializableUserC userCs = ProtoStuffSerializerUtil.deserialize(arr, org.wit.ff.testmodel.ch1.SerializableUserC.class);
        System.out.println(userCs);
        assertNotNull(userCs);
        // 屬性類型不匹配時發生異常!
        try{
            ProtoStuffSerializerUtil.deserialize(arr, org.wit.ff.testmodel.ch.SerializableUserC.class);
        }catch(Exception e){
            e.printStackTrace();
            assertTrue(true);
        }
        
    }
}

 


免責聲明!

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



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