Java對象序列化小結

原創文章,轉載時請註明做者:jmppok 及 出處 Java對象序列化小結
java


在Java中常常會用到對象序列化的地方,好比在持久化存儲對象時,傳輸對象時等。目前Java對象的序列化有不少種,可參見「Java序列化工具大全及性能比較」,但我的認爲大體可分爲4類:json

1)序列化對象須要事先實現Serializable接口的,如Java原生的序列化,Hessian, FST-serialization等等。

優勢是:能夠本身控制Serializable的實現,十分靈活,用戶能夠本身控制序列化的內容,順序等等,若是實現比較好的話,體積小,效率高。數據結構

缺點是:序列化對象必須事先實現Serializable接口,限制比較大。而且用戶需事先實現Serializable接口,工做量相對較大。工具

我的不太推薦。性能


2)使用某種中間語言,事先定義對象的Schema,而後生成相應的Java/C++/Python代碼, 如goole的protobuffer,flatbuffer,thrift,ice等等。

優勢是:用戶經過中間語言定義數據結構,能夠生成大部分語言(C/C++/Java/C#/Python/Javascript等等)對應的代碼,使用起來十分方便,且序列化效率高,體積小。測試

缺點是:用戶需事先定義數據結構,由於限制了使用範圍。
this

通常推薦。spa


3)  經過開源工具,將對象直接序列化爲XML,JSON等,如gson,fastjson等。

優勢是:可序列化任意的Java對象。.net

缺點是:效率相對較低,序列化後體積較大。在反序列化時,必需要指定須要反序列化的數據的Class,我的認這一點很是不爽。code

以下所示:

Persion類

public class Persion {
    public String name;
    public int    age;

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Persion() {

    }
}

Gson序列化/反序列化測試

public class TestGson {

    /**
     * @author ligh4 2015年3月19日下午5:32:34
     * @param args
     */
    public static void main(String[] args) throws Exception {

        Map<Integer, Map<String, Persion>> classes = new Hashtable<Integer, Map<String, Persion>>();

        Map<String, Persion> map = new HashMap<String, Persion>();
        map.put("ligh1", new Persion("ligh1", 30));
        map.put("ligh2", new Persion("ligh2", 30));

        classes.put(1, map);

        String json = new Gson().toJson(classes);

        Map<Integer, Map<String, Persion>> cls = new Gson().fromJson(json,
                new TypeToken<Map<Integer, Map<String, Persion>>>() {
                }.getType());

        System.out.println(cls.get(1).get("ligh2").name);

    }
}

看到Gson反序列化時了麼?

Map<Integer, Map<String, Persion>> cls = new Gson().fromJson(json,
                new TypeToken<Map<Integer, Map<String, Persion>>>() {
                }.getType());

好像很不爽阿?不過相比須要事先實現Serializable接口和實現定義Schema生成代碼,忍了。


實際上,在計算機硬件性能和帶寬高速發展的今天,對序列化的效率和數據大小的追求逐漸降低。大部分公司追求的是項目的短,平,快,所以gson等序列化工具成爲你們的首選。

十分推薦。


4)我的認爲的終極序列化工具, 序列化任意對象。且在序列化反序列化時不須要人爲指定類的信息,如Kryo。

費話很少說,直接上代碼:

public static void main (String[] args) throws Exception {


		Map<String, Persion> map = new HashMap<String, MapTest.Persion>();
		map.put("ligh1", new Persion("ligh1", 30));
		map.put("ligh2", new Persion("ligh2", 30));

		Map<Integer, Map<String, Persion>> classes = new Hashtable<Integer, Map<String, Persion>>();

		classes.put(1, map);


		Kryo kryo = new Kryo();

		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		Output output = new Output(buffer);
		kryo.writeClassAndObject(output, classes);
		output.flush();

		byte[] datas = buffer.toByteArray();
		System.out.println(datas.length);

		Input input = new Input(datas);

		Map<String, Persion> map2 = (Map)((Map)kryo.readClassAndObject(input)).get(1);
		Persion p1 = map2.get("ligh2");
	}

看到強大之處了吧?

kryo.writeClassAndObject(output, classes);
<pre name="code" class="java">kryo.readClassAndObject(input);

 使用十分方便。 

不過什麼Output,Input貌似也有點Out了,來一個簡單的封裝:

public class ObjectSerialization {

    /**
     * @author ligh4 2015年3月23日下午1:32:04
     * @param obj
     * @return null if failed.
     * @throws Exception
     */
    public static synchronized String ToString(Object obj) {
        Kryo kryo = new Kryo();

        ByteOutputStream stream = new ByteOutputStream();
        Output output = new Output(stream);
        kryo.writeClassAndObject(output, obj);
        output.flush();

        String str = null;
        try {
            byte[] bytes = stream.getBytes();
            str = new String(bytes, "ISO8859-1");
        } catch (Exception e) {
            str = null;
        } finally {
            output.close();
            stream.close();
        }

        return str;
    }

    /**
     * @author ligh4 2015年3月23日下午1:32:19
     * @param str
     * @return null if failed.
     * @throws Exception
     */
    public static synchronized Object FromString(String str) {

        Kryo kryo = new Kryo();

        try {
            byte[] bytes = str.getBytes("ISO8859-1");
            Input input = new Input(bytes);
            Object obj = kryo.readClassAndObject(input);
            input.close();
            return obj;
        } catch (Exception e) {
            return null;
        }

    }

    static class Persion {
        public String name;
        public int    age;

        public Persion(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public Persion() {

        }
    }

    /**
     * @author ligh4 2015年3月20日下午4:07:50
     * @param args
     */
    @SuppressWarnings({ "unchecked", "rawtypes", "unused" })
    public static void main(String[] args) throws Exception {

        Map<String, Persion> map = new HashMap<String, Persion>();
        map.put("cn1", new Persion("中國1", 30));
        map.put("cn2", new Persion("中國2", 30));

        Map<Integer, Map<String, Persion>> classes = new HashMap<Integer, Map<String, Persion>>();

        classes.put(1, map);

        String str = ObjectSerialization.ToString(classes);

        System.out.println(str.length() + ":" + str);

        Map<String, Persion> map2 = (Map) ((Map) ObjectSerialization.FromString(str)).get(1);

        Persion p1 = map2.get("cn2");
    }
}

使用更加方便了:

String str = ObjectSerialization.ToString(classes);
ObjectSerialization.FromString(str)).get(1);
相關文章
相關標籤/搜索