前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >dubbo序列化问题(一)浮点数问题

dubbo序列化问题(一)浮点数问题

作者头像
一笠风雨任生平
发布2019-08-02 11:29:43
1.3K0
发布2019-08-02 11:29:43
举报
文章被收录于专栏:服务化进程服务化进程

dubbo是一个分布式服务框架,在国内比较常用,在开发过程中遇到一个浮点数反序列化问题。

问题描述,当参数是float类型的3.7,反序列化却得到了一个double类型的值:3.700000047683716。

然后,我写了个测试程序:

代码语言:javascript
复制
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;


import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;


public class TestHessionLite {


	public static void main(String[] args) throws IOException {
		HashMap<String,Float> map=new HashMap<String,Float>();
		Float loat=new Float(3.7);
		map.put("3.7", loat);
		
		byte[] aa=TestHessionLite.serialize(map);
		Object mm=TestHessionLite.deserialize(aa);
		System.out.println(mm.toString());
		
	}
	
	public static byte[] serialize(Object obj) throws IOException{  
		 ByteArrayOutputStream os = new ByteArrayOutputStream(); 
		 Hessian2Output ho = new Hessian2Output(os);  
		 byte[] cc = null;
		try {
			if(obj==null) throw new NullPointerException();  
		    ho.writeObject(obj);
		    ho.flushBuffer();
		    cc=os.toByteArray();  
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			ho.close();
		}
		return cc;  
	    
	} 
	
	public static Object deserialize(byte[] by) throws IOException{ 
		try {
			if(by==null) throw new NullPointerException();  
			ByteArrayInputStream is = new ByteArrayInputStream(by);
		    Hessian2Input hi = new Hessian2Input(is);  
		    return hi.readObject();  
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	    
	}  
}

输出结果为

代码语言:javascript
复制
{3.7=3.700000047683716}

然后由分别使用3.5、3.6进行测试

代码语言:javascript
复制
{3.6=3.5999999046325684}
{3.5=3.5}

经过测试,并不是所有小数都有问题,部分小数会出现序列化问题。

我的dubbo服务序列化使用的是dubbo默认的hession2,而使用hessian2协议,也就是传输对象序列化,它是二进制的RPC协议。

经过分析,问题应该是出在了十进制浮点数转二进制。

后面又查看了相关资料,以及写了十进制和二进制互转的测试程序发现,就是不分小数在float单精度下是无法表示出来的。具体原因可以见下面资料http://blog.csdn.net/zcczcw/article/details/7362473。

如果将float,改成double,就不存在刚才精度问题了,因为double是双精度,可以保存64位二进制;

但是当小数点超过8位时,double也会被截取。

而是用kryo进行序列化则不会出现上面问题,因为kryo不是通过二进制存储,是通过字节数组来进行存储,这样可以保证数据不用进行转化。

代码语言:javascript
复制
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;

import org.apache.commons.codec.binary.Base64;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.JavaSerializer;

public class TestKryo {

	public static void main(String[] args) {

		HashMap<String,Float> map=new HashMap<String,Float>();
		Float loat=new Float(3.7);
		map.put("value", loat);
		
		String aa=TestKryo.serialize(map);
		Object mm=TestKryo.deserialize(aa,HashMap.class);
		System.out.println(mm.toString());
	}
	private static <T extends Serializable> String serialize(T obj) {
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.register(obj.getClass(), new JavaSerializer());
 
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Output output = new Output(baos);
        kryo.writeClassAndObject(output, obj);
        output.flush();
        output.close();
 
        byte[] b = baos.toByteArray();
        try {
            baos.flush();
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        return new String(new Base64().encode(b));
    }
 
    @SuppressWarnings("unchecked")
    private static <T extends Serializable> T deserialize(String obj,
            Class<T> clazz) {
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.register(clazz, new JavaSerializer());
 
        ByteArrayInputStream bais = new ByteArrayInputStream(
                new Base64().decode(obj));
        Input input = new Input(bais);
        return (T) kryo.readClassAndObject(input);
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档