java编解码技术

一.编解码技术


       基于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;


@Message
public 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).测试结果





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值