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.Status());
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使⽤有问题的,可以看我的另⼀篇博客
3 反射的⽅式
第⼀种⽅法的缺点在于,每⼀个类都要这么写⼀个toByteArray⽅法。如果类多了是⾮常⿇烦的。有什么⽅便的⽅法吗?当然是有的,利⽤反射的⽅式(只会在第⼀次反射,后⾯会做本地缓存,所以性能开销不⼤)。需要在⼀个⽂件夹下添加下⾯五个类
1.Codecable
import com.fasterxml.jackson.annotation.JsonIgnore;
llect.Lists;
import lombok.Data;
import flect.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 = DeclaredFields();
List<FieldWrapper> fieldWrapperList = wArrayList();
for (Field field : fields) {
CodecProprety codecProprety = Annotation(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) {
CodecProprety().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 flect.Field;
@Data
@AllArgsConstructor
public class FieldWrapper {
/**
* 上下⾏数据属性
*/
private Field field;
/**
* 上下⾏数据属性上的注解
*/
private CodecProprety codecProprety;
}
4.PayloadDecoder
import ioty.buffer.ByteBuf;
import ioty.buffer.Unpooled;
import flect.Field;
import flect.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 = wInstance();
} catch (Exception e) {
throw new RuntimeException("实例化类失败", e);
}
List<FieldWrapper> fieldWrapperList = FieldWrapperList();
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 = Field();
field.setAccessible(true);
String typeName = Type().getName();
try {
switch (typeName) {
case "java.lang.Boolean":
case "boolean":
boolean b = adBoolean();
field.set(instance, b);
break;
case "java.lang.Character":
case "char":
CharSequence charSequence = CodecProprety().length(), Charset.forName("UTF-8")); field.set(instance, charSequence);
break;
case "java.lang.Byte":
case "byte":
byte b1 = adByte();
field.set(instance, b1);
break;
case "java.lang.Short":
case "short":
short readShort = adShort();
field.set(instance, readShort);
break;
case "java.lang.Integer":
case "int":
int readInt = adInt();
field.set(instance, readInt);
break;
case "java.lang.Long":
case "long":
long l = adLong();
field.set(instance, l);
break;
case "java.lang.Float":
case "float":
float readFloat = adFloat();
field.set(instance, readFloat);
break;
case "java.lang.Double":
case "double":
double readDouble = adDouble();
field.set(instance, readDouble);
break;
case "java.lang.String":
String readString = CodecProprety().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:" + Name(), e);
}
}
}
5.PayloadEncoder
import ioty.buffer.ByteBuf;
import ioty.buffer.Unpooled;
import flect.Field;
import flect.Method;
import java.nio.charset.Charset;
import java.util.List;
public class PayloadEncoder {
public static <T extends Codecable> byte[] getPayload(T command) {
java数组字符串转数组List<FieldWrapper> fieldWrapperList = FieldWrapperList();
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 = Field();
String typeName = Type().getName();
field.setAccessible(true);
Object value = null;
try {
value = (instance);
} catch (IllegalAccessException e) {
new RuntimeException("反射获取值失败,filed:" + Name(), 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数组。
4 总结
可能会有⼈问了,上⾯三种,明显第⼆种转json最简单,为什么还要⽤另外两种呢?
其实,第⼀种和第三种可以归为⼀类,都是把对象直接转成byte数组,下⼀层做解析的话,可以⼀个⼀个元素取;
第⼆种情况是把对象的json字符串转成byte数组,问题就在于,json字符串最开头是”{“,也就是转成的byte数组的第⼀位是”{“对应的数值
在使⽤中应该根据情况来,如果下⼀层做解析是直接取元素,对象少的话⽤第⼀种;对象多的话⽤第三种;
如果下⼀层做了排除掉json的⼀些格式的解析,就⽤第⼆种。
以上全部为本篇⽂章的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论