java编解码技术

来源:互联网 发布:网络教育试点高校 编辑:程序博客网 时间:2024/05/15 02:25

一.编解码技术


       基于Java提供的对象输入/输出ObjectInputStream和ObjectOutputStream,可以直接把Java对象作为可存储的字节数组写入文件,也可以传输到网络上,对于程序员来说,基于JDK默认的序列化机制可以避免操作底层字节数组,从而提升开发效率。

      当进行进程跨进程的调用时,需要把被传输的Java对象编码为字节数组或者ByteBuffer对象,而当远程服务收到字节数组或者ByteBuffer时,需要将其解码为Java对象。这被称为Java对象编解码技术。


二.Java序列化


      Java序列化从JDK1.1版本就已经提供,只需要实现java.io.Serializable即可,但是进行远程服务调用(RPC)时,却很少使用Java序列化进行消息的编解编码和传输,主要原因是:
     1). 无法跨语言,Java序列化技术是Java语言内部的私有协议,其他语言并不支持,对于Java序列化后的字节数组,别的语言无法进行反序列化,这就严重阻碍它的应用。
     2). 序列化后流太大
     3).序列化性能太低

 

ps一句其他的:

1).  Serializable序列化生成serialVersionUID的两种方式,一个是默认的1L,另一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。
 2).  显示设置serialVersionUID 与不设置serialVersionUID的区别,显示设置serialVersionUID确保了不同版本之间的兼容性,不仅能够向前兼容,还能够向后兼容,即在版 升级时反序列化仍保持对象的唯一 性 ; 不设置serialVersionUID时,默认生成一个serialVersionUID,本地实体类有修改后又生成 一个serialVersionUID,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致 的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException);
3).  声明为transient类型的成员数据不能被序列化。transient代表对象的临时数据;  
    

三.Java序列和ByteBuffer的二进制序列对比


1). 待序列化类

package com.phei.netty;import java.io.Serializable;public class UserInfo implements Serializable  {private static final long serialVersionUID = -5867548109897989552L;    private String userName;    private int userID;    public UserInfo(String userName,int userID){    this.userName = userName;    this.userID = userID;    }public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public int getUserID() {return userID;}public void setUserID(int userID) {this.userID = userID;}    }

 2).测试类

  

<pre name="code" class="java">package com.phei.netty;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.nio.ByteBuffer;public class UserInfoTest   {public static void main(String args[]) throws IOException{UserInfo user = new UserInfo("Hello World", 666666);System.out.println("/*-------------------序列号字节流长度对比--------------------------*/");ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(user);oos.flush();oos.close();byte [] b = bos.toByteArray();System.out.println("Java jdk自带的序列化字节流的大小"+b.length);bos.close();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put(user.getUserName().getBytes());buffer.putInt(user.getUserID());buffer.flip();byte [] result = new byte[buffer.remaining()];buffer.get(result);System.out.println("ByteBuffer的二进制压缩后字节流的大小"+result.length);System.out.println();System.out.println("/*-------------------序列号性能对比--------------------------*/");long startTimeMillis = System.currentTimeMillis();for(int i=0;i<1000;i++){ByteArrayOutputStream bo = new ByteArrayOutputStream();ObjectOutputStream oo = new ObjectOutputStream(bos);oos.writeObject(user);oos.flush();oos.close();byte [] bb = bos.toByteArray();bos.close();}System.out.println("Java 自带序列化花费时间:"+(System.currentTimeMillis()-startTimeMillis));long startTimeMil = System.currentTimeMillis();for(int i=0;i<1000;i++){ByteBuffer buf = ByteBuffer.allocate(1024);buf.put(user.getUserName().getBytes());buf.putInt(user.getUserID());buf.flip();byte [] res = new byte[buf.remaining()];buf.get(res);}System.out.println("ByteBuffer的序列化花费时间:"+(System.currentTimeMillis()-startTimeMil)); }    }

3).对比结果

  呵呵,看看结果,还是挺吓人的

   

四.Google Protobuf编解码

        Protobuf是一个灵活、高效、结构化的数据序列化架构,相比于XML等传统的序列化工具,他更小、更快、更简单。Protobuf支持数据结构化一次即可到处使用,甚至跨语    言,通过代码生成工具可以自动生成不同语言版本的源代码,甚至可以使用不同版本的数据结构进程间进行数据传递,实现数据结构的向前兼容。

1). 下载Protobuf地址

 http://download.csdn.net/detail/dfdsggdgg/9507327

2).编写.proto文件

 
package com.leehongee.netserver.net.bean;option java_package = "com.phei.netty.protobuf";option java_outer_classname = "UserInfo"; message User{ required int32 userID = 1; required string userName = 2;       }

3).CMD命令编译.proto文件

    D:\protobuf\protobuf-2.5.0>protoc.exe  --java_out=./ hello.proto
    命令执行后,在目录com\leehongee\netserver\net\bean 目录下将生成一个.java源文件。

4).工程引入protobuf-java-2.5.0.jar,再将刚才生成的.java文件放入对应的包目录下,编写测试类


package com.phei.netty.protobuf;import java.io.IOException;import com.google.protobuf.InvalidProtocolBufferException;public class UserInfoTest {private static byte[] encode(UserInfo.User user){return user.toByteArray();}/** * 反序列化 * @param body * @return * @throws InvalidProtocolBufferException */private static UserInfo.User decode(byte[] body) throws InvalidProtocolBufferException{return UserInfo.User.parseFrom(body);}/** * 序列化 * @return */private static UserInfo.User createUser(){UserInfo.User.Builder builder = UserInfo.User.newBuilder();builder.setUserID(666666);builder.setUserName("hello world");return builder.build();} public static void main(String[] args) throws IOException {UserInfo.User user = createUser();System.out.println("protobuf序列化后字节流大小"+user.toByteArray().length);System.out.println("Before encode : "+ user.toString());System.out.println(encode(user).length);UserInfo.User user2 = decode(encode(user)); System.out.println("After decode : "+ user.toString());}}

5).测试结果




五.MessagePack编解码

      
       MessagePack是一个高效的二进制序列化框架,它像JSON一样支持不同的语言的数据交换,但是他的性能更快,序列化后的流更小。

1). 下载MessagePack jar包


    http://download.csdn.net/detail/dfdsggdgg/9507386


2).编写测试类


UserInfo类
</pre><pre name="code" class="java">package com.phei.netty.messagepack;import org.msgpack.annotation.Message;@Messagepublic class UserInfo{    public String userName;    public int userID;        }

UserInfoTest类   
package com.phei.netty.messagepack;import java.io.IOException;import org.msgpack.MessagePack;public class UserInfoTest   {   public static void main(String args[]) throws IOException{ UserInfo user = new UserInfo(); user.userID=666666; user.userName="hello world"; MessagePack pack = new MessagePack();     //序列化     byte[] bytes = pack.write(user);     System.out.println("MessagePack序列化后字节流大小:"+bytes.length);         //反序列化     UserInfo u = pack.read(bytes, UserInfo.class);     System.out.println("DeviceID: "+u.userName); }    }

3).测试结果





1 0
原创粉丝点击