zoukankan      html  css  js  c++  java
  • 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);
            }
            
        }
    }
  • 相关阅读:
    window XP下 php5.5+mysql+apache2+phpmyadmin安装
    poj2478Farey Sequence
    poj2723Get Luffy Out
    niop2015day2
    P2473 [SCOI2008]奖励关
    P4284 [SHOI2014]概率充电器
    P2486 [SDOI2011]染色
    noip2015day1
    hdu 2795 Billboard
    exgcd
  • 原文地址:https://www.cnblogs.com/fangfan/p/4094175.html
Copyright © 2011-2022 走看看