IT虾米网

Java序列化技术与Protobuff详解

sanshao 2021年10月13日 编程语言 146 0
本文章主要介绍了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

     官网:IT虾米网

     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); 
        } 
         
    } 
}

发布评论
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Linux 查找大于100M的文件详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。