java对象转成byte数组的3种方法
java对象转成byte数组,在使用netty进行通信协议传输的场景中是非常常见的。比如,协议有一些定好的协议头、classid,messageid等等信息,还有一个关键的内容是payload。不同的协议内容都会放到payload中,而这个payload往往就是一个byte数组。
那么,如何方便的将一个java对象构造成一个byte数组呢?
1 bytebuf填充
我们以下面这个对象举例:
public class ugvdata implements serializible{ private static final long serialversionuid = -219988432063763456l; //状态码 byte status; //当前gps经度 float longitude; //当前gps纬度 float latitude; //行驶速度 单位是 m/s,带一个小数点 float speed; //当前电量百分比 short batterypercentage; //任务编号 long quest; public byte[] tobytearray() { bytebuf buf = unpooled.buffer(32); buf.writebyte(this.getstatus()); buf.writefloat(getlongitude()); buf.writefloat(getlatitude()); buf.writefloat(getspeed()); buf.writeshort(getbatterypercentage()); buf.writelong(getquest()); return buf.array(); } //省略get set }
那么只需要new出一个上面的对象,调用其tobytearray方法,即可将这个对象转成byte数组。
2 巧用json
我们都知道,字符串是可以转成byte数组的。将一个对象转成json字符串也很容易,直接使用fastjson就可以了。如果对fastjson使用有问题的,可以看我的另一篇博客json.parseobject 和 json.tojsonstring 实例
json.tojsonstring(ugvdata).getbytes()
3 反射的方式
第一种方法的缺点在于,每一个类都要这么写一个tobytearray方法。如果类多了是非常麻烦的。有什么方便的方法吗?当然是有的,利用反射的方式(只会在第一次反射,后面会做本地缓存,所以性能开销不大)。需要在一个文件夹下添加下面五个类
1.codecable
import com.fasterxml.jackson.annotation.jsonignore; import com.google.common.collect.lists; import lombok.data; import java.lang.reflect.field; import java.util.collections; import java.util.comparator; import java.util.list; @data public abstract class codecable { public static list<fieldwrapper> resolvefileldwrapperlist(class clazz){ field[] fields = clazz.getdeclaredfields(); list<fieldwrapper> fieldwrapperlist = lists.newarraylist(); for (field field : fields) { codecproprety codecproprety = field.getannotation(codecproprety.class); if (codecproprety == null) { continue; } fieldwrapper fw = new fieldwrapper(field, codecproprety); fieldwrapperlist.add(fw); } collections.sort(fieldwrapperlist, new comparator<fieldwrapper>() { @override public int compare(fieldwrapper o1, fieldwrapper o2) { return o1.getcodecproprety().order() - o2.getcodecproprety().order(); } }); return fieldwrapperlist; } @jsonignore public abstract list<fieldwrapper> getfieldwrapperlist(); }
2.codecproprety
import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; @retention(retentionpolicy.runtime) @target({elementtype.field}) public @interface codecproprety { /** * 属性顺序 * @return */ int order(); /** * 数据长度。解码时用,除了简单数据类型之外才起作用(如:string)。 * @return */ int length() default 0; }
3.fieldwrapper
import lombok.allargsconstructor; import lombok.data; import java.lang.reflect.field; @data @allargsconstructor public class fieldwrapper { /** * 上下行数据属性 */ private field field; /** * 上下行数据属性上的注解 */ private codecproprety codecproprety; }
4.payloaddecoder
import io.netty.buffer.bytebuf; import io.netty.buffer.unpooled; import java.lang.reflect.field; import java.lang.reflect.method; import java.nio.charset.charset; import java.util.list; public class payloaddecoder { public static <t extends codecable> t resolve(byte[] src, class<t> clazz) { t instance = null; try { instance = clazz.newinstance(); } catch (exception e) { throw new runtimeexception("实例化类失败", e); } list<fieldwrapper> fieldwrapperlist = instance.getfieldwrapperlist(); bytebuf buffer = unpooled.buffer().writebytes(src); for (fieldwrapper fieldwrapper : fieldwrapperlist) { filldata(fieldwrapper, instance, buffer); } return instance; } private static void filldata(fieldwrapper fieldwrapper, object instance, bytebuf buffer) { field field = fieldwrapper.getfield(); field.setaccessible(true); string typename = field.gettype().getname(); try { switch (typename) { case "java.lang.boolean": case "boolean": boolean b = buffer.readboolean(); field.set(instance, b); break; case "java.lang.character": case "char": charsequence charsequence = buffer.readcharsequence(fieldwrapper.getcodecproprety().length(), charset.forname("utf-8")); field.set(instance, charsequence); break; case "java.lang.byte": case "byte": byte b1 = buffer.readbyte(); field.set(instance, b1); break; case "java.lang.short": case "short": short readshort = buffer.readshort(); field.set(instance, readshort); break; case "java.lang.integer": case "int": int readint = buffer.readint(); field.set(instance, readint); break; case "java.lang.long": case "long": long l = buffer.readlong(); field.set(instance, l); break; case "java.lang.float": case "float": float readfloat = buffer.readfloat(); field.set(instance, readfloat); break; case "java.lang.double": case "double": double readdouble = buffer.readdouble(); field.set(instance, readdouble); break; case "java.lang.string": string readstring = buffer.readcharsequence(fieldwrapper.getcodecproprety().length(), charset.forname("utf-8")).tostring(); field.set(instance, readstring); break; default: throw new runtimeexception(typename + "不支持,bug"); } } catch (exception e) { throw new runtimeexception(typename + "读取失败,field:" + field.getname(), e); } } }
5.payloadencoder
import io.netty.buffer.bytebuf; import io.netty.buffer.unpooled; import java.lang.reflect.field; import java.lang.reflect.method; import java.nio.charset.charset; import java.util.list; public class payloadencoder { public static <t extends codecable> byte[] getpayload(t command) { list<fieldwrapper> fieldwrapperlist = command.getfieldwrapperlist(); bytebuf buffer = unpooled.buffer(); fieldwrapperlist.foreach(fieldwrapper -> write2bytebuf(fieldwrapper, command, buffer)); return buffer.array(); } /** * 数据写入到bytebuf * * @param fieldwrapper * @param instance * @param buffer */ private static void write2bytebuf(fieldwrapper fieldwrapper, object instance, bytebuf buffer) { field field = fieldwrapper.getfield(); string typename = field.gettype().getname(); field.setaccessible(true); object value = null; try { value = field.get(instance); } catch (illegalaccessexception e) { new runtimeexception("反射获取值失败,filed:" + field.getname(), e); } switch (typename) { case "java.lang.boolean": case "boolean": buffer.writeboolean((boolean) value); break; case "java.lang.character": case "char": buffer.writecharsequence((charsequence) value, charset.forname("utf-8")); break; case "java.lang.byte": case "byte": buffer.writebyte((byte) value); break; case "java.lang.short": case "short": buffer.writeshort((short) value); break; case "java.lang.integer": case "int": buffer.writeint((int) value); break; case "java.lang.long": case "long": buffer.writelong((long) value); break; case "java.lang.float": case "float": buffer.writefloat((float) value); break; case "java.lang.double": case "double": buffer.writedouble((double) value); break; case "java.lang.string": buffer.writecharsequence((charsequence) value, charset.forname("utf-8")); break; default: throw new runtimeexception(typename + "不支持,bug"); } } }
添加完上面五个类之后,使用也很简单,只需要如下所示,就可以把drivestartdata转成byte数组。
payloadencoder.getpayload(drivestartdata)
4 总结
可能会有人问了,上面三种,明显第二种转json最简单,为什么还要用另外两种呢?
其实,第一种和第三种可以归为一类,都是把对象直接转成byte数组,下一层做解析的话,可以一个一个元素取;
第二种情况是把对象的json字符串转成byte数组,问题就在于,json字符串最开头是”{“,也就是转成的byte数组的第一位是”{“对应的数值
在使用中应该根据情况来,如果下一层做解析是直接取元素,对象少的话用第一种;对象多的话用第三种;
如果下一层做了排除掉json的一些格式的解析,就用第二种。
以上全部为本篇文章的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: VS2013设置护眼背景颜色
下一篇: jsp源码实例5(cookie)