前言:
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); } } }