反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
一般我们实现序列化与反序列化,会使用Java中的Serialization 接口。下面使用三种方式进行序列化与反序列化。
(1)单一的Int 数据进行序列化与反序列化(普通方法)
这里涉及了大小端字节序列
端模式分为:小端字节序和大端字节序,也就是字节在内存中的顺序。
小端字节序:低字节存于内存低地址;高字节存于内存高地址。如一个long型数据0x12345678
0x0029f458 0x78
0x0029f459 0x56
0x0029f45a 0x34
0x0029f45b 0x12
在以上数据存放于内存中的表现形式中,0x0029f458 < 0x0029f459 < 0x0029f45a < 0x0029f45b,
可以知道内存的地址是由低到高的顺序;而数据的字节也是由低到高的,故以上字节序是小端字节序。
大端字节序:高字节存于内存低地址;低字节存于内存高地址。
0x0029f458 0x12
0x0029f459 0x34
0x0029f45a 0x56
0x0029f45b 0x79
在以上数据存放于内存中的表现形式中,0x0029f458 < 0x0029f459 < 0x0029f45a < 0x0029f45b,
可以知道内存的地址是由低到高的顺序;而数据的字节却是由高到低的,故以上字节序是大端字节序。
网络字节序:就是大端字节序。规定不同系统间通信一律采用网络字节序。
可以参考: https://blog.csdn.net/qq_33724710/article/details/51056542
序列化方法:(这里采用的是大端字节序:先写高位,再写低位)
/**
* 大端字节序列, (先写高位,再写地位)
* 大小端字节序列
* @param i
* @return
*/
public static byte[] int2bytes(int i){
byte[] bytes = new byte[4];
//先写高位,再写低位
bytes[0] = (byte)(i >> 3*8);
bytes[1] = (byte)(i >> 2*8);
bytes[2] = (byte)(i >> 1*8);
bytes[3] = (byte)(i >> 0*8);
return bytes;
}
反序列化:(由于序列化过程为大端字节序列,所以在反序列过程同样使用)
public static int bytes2int(byte[] bytes){
return (bytes[0] << 3*8) |
(bytes[1] << 2*8)|
(bytes[2] << 1*8)|
(bytes[3] << 0*8);
}
测试:
public static void main(String[] args) throws IOException {
int i = 2;
int age = 4;
ByteArrayOutputStream byStream = new ByteArrayOutputStream();
byStream.write(int2bytes(i));
byStream.write(int2bytes(age));
byte[] bytearrays = byStream.toByteArray();
System.out.println(Arrays.toString(bytearrays));
// 还原
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytearrays);
byte[] byteid = new byte[4];
byteArrayInputStream.read(byteid);
System.out.println("id+"+ bytes2int(byteid));
byte[] byteage = new byte[4];
byteArrayInputStream.read(byteage);
System.out.println("age+"+ bytes2int(byteage));
}
(2) 使用Nio 进行序列化
弊端:不能自动扩容 需要指定 大小。例如下面的ByteBuffer.allocate(8); 代表了两个int 数据的字节大小
public static void main(String[] args) {
int i = 22;
int age = 23;
// 序列化
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
byteBuffer.putInt(i);
byteBuffer.putInt(age);
byte[] array = byteBuffer.array();
System.out.println(Arrays.toString(array));
// 反序列化
ByteBuffer byteBuffer2 = ByteBuffer.wrap(array);
System.out.println(byteBuffer2.getInt());
System.out.println(byteBuffer2.getInt());
}
(3) 为了解决上面的弊端我们需要进行动态的知道我们传入数据的字节大小。Netty 3 中的ChannelBuffer 可以解决这个问题
public static void main(String[] args) {
//序列化
ChannelBuffer cBuffer = ChannelBuffers.dynamicBuffer();
cBuffer.writeInt(23);
cBuffer.writeInt(24);
cBuffer.writeLong(123);
byte[] bytes = new byte[cBuffer.writerIndex()];
cBuffer.readBytes(bytes);
System.out.println(Arrays.toString(bytes));
// 反序列化
ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(bytes);
System.out.println(buffer.readInt());
System.out.println(buffer.readInt());
System.out.println(buffer.readLong());
}
为了可以很好的使用复用。我们将Netty3 中提供的接口 构建成一个工具类。
Buffer工厂
BufferFactory
package com.core;
import java.nio.ByteOrder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
/**
* buff工厂
*
*/
public class BufferFactory {
public static ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;
/**
* 获取一个buffer
*
* @return
*/
public static ChannelBuffer getBuffer() {
ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer();
return dynamicBuffer;
}
/**
* 将数据写入buffer
* @param bytes
* @return
*/
public static ChannelBuffer getBuffer(byte[] bytes) {
ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes);
return copiedBuffer;
}
}
抽象的序列化接口:Serializer
package com.core;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jboss.netty.buffer.ChannelBuffer;
/**
* 自定义序列化接口
*
*/
public abstract class Serializer {
public static final Charset CHARSET = Charset.forName("UTF-8");
protected ChannelBuffer writeBuffer;
protected ChannelBuffer readBuffer;
/**
* 反序列化具体实现
*/
protected abstract void read();
/**
* 序列化具体实现
*/
protected abstract void write();
/**
* 从byte数组获取数据
* @param bytes 读取的数组
*/
public Serializer readFromBytes(byte[] bytes) {
readBuffer = BufferFactory.getBuffer(bytes);
read();
readBuffer.clear();
return this;
}
/**
* 从buff获取数据
* @param readBuffer
*/
public void readFromBuffer(ChannelBuffer readBuffer) {
this.readBuffer = readBuffer;
read();
}
/**
* 写入本地buff
* @return
*/
public ChannelBuffer writeToLocalBuff(){
writeBuffer = BufferFactory.getBuffer();
write();
return writeBuffer;
}
/**
* 写入目标buff
* @param buffer
* @return
*/
public ChannelBuffer writeToTargetBuff(ChannelBuffer buffer){
writeBuffer = buffer;
write();
return writeBuffer;
}
/**
* 返回buffer数组
*
* @return
*/
public byte[] getBytes() {
writeToLocalBuff();
byte[] bytes = null;
if (writeBuffer.writerIndex() == 0) {
bytes = new byte[0];
} else {
bytes = new byte[writeBuffer.writerIndex()];
writeBuffer.readBytes(bytes);
}
writeBuffer.clear();
return bytes;
}
public byte readByte() {
return readBuffer.readByte();
}
public short readShort() {
return readBuffer.readShort();
}
public int readInt() {
return readBuffer.readInt();
}
public long readLong() {
return readBuffer.readLong();
}
public float readFloat() {
return readBuffer.readFloat();
}
public double readDouble() {
return readBuffer.readDouble();
}
public String readString() {
int size = readBuffer.readShort();
if (size <= 0) {
return "";
}
byte[] bytes = new byte[size];
readBuffer.readBytes(bytes);
return new String(bytes, CHARSET);
}
public <T> List<T> readList(Class<T> clz) {
List<T> list = new ArrayList<>();
int size = readBuffer.readShort();
for (int i = 0; i < size; i++) {
list.add(read(clz));
}
return list;
}
public <K,V> Map<K,V> readMap(Class<K> keyClz, Class<V> valueClz) {
Map<K,V> map = new HashMap<>();
int size = readBuffer.readShort();
for (int i = 0; i < size; i++) {
K key = read(keyClz);
V value = read(valueClz);
map.put(key, value);
}
return map;
}
@SuppressWarnings("unchecked")
public <I> I read(Class<I> clz) {
Object t = null;
if ( clz == int.class || clz == Integer.class) {
t = this.readInt();
} else if (clz == byte.class || clz == Byte.class){
t = this.readByte();
} else if (clz == short.class || clz == Short.class){
t = this.readShort();
} else if (clz == long.class || clz == Long.class){
t = this.readLong();
} else if (clz == float.class || clz == Float.class){
t = readFloat();
} else if (clz == double.class || clz == Double.class){
t = readDouble();
} else if (clz == String.class ){
t = readString();
} else if (Serializer.class.isAssignableFrom(clz)){
try {
byte hasObject = this.readBuffer.readByte();
if(hasObject == 1){
Serializer temp = (Serializer)clz.newInstance();
temp.readFromBuffer(this.readBuffer);
t = temp;
}else{
t = null;
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
throw new RuntimeException(String.format("不支持类型:[%s]", clz));
}
return (I) t;
}
public Serializer writeByte(Byte value) {
writeBuffer.writeByte(value);
return this;
}
public Serializer writeShort(Short value) {
writeBuffer.writeShort(value);
return this;
}
public Serializer writeInt(Integer value) {
writeBuffer.writeInt(value);
return this;
}
public Serializer writeLong(Long value) {
writeBuffer.writeLong(value);
return this;
}
public Serializer writeFloat(Float value) {
writeBuffer.writeFloat(value);
return this;
}
public Serializer writeDouble(Double value) {
writeBuffer.writeDouble(value);
return this;
}
public <T> Serializer writeList(List<T> list) {
if (isEmpty(list)) {
writeBuffer.writeShort((short) 0);
return this;
}
writeBuffer.writeShort((short) list.size());
for (T item : list) {
writeObject(item);
}
return this;
}
public <K,V> Serializer writeMap(Map<K, V> map) {
if (isEmpty(map)) {
writeBuffer.writeShort((short) 0);
return this;
}
writeBuffer.writeShort((short) map.size());
for (Entry<K, V> entry : map.entrySet()) {
writeObject(entry.getKey());
writeObject(entry.getValue());
}
return this;
}
public Serializer writeString(String value) {
if (value == null || value.isEmpty()) {
writeShort((short) 0);
return this;
}
byte data[] = value.getBytes(CHARSET);
short len = (short) data.length;
writeBuffer.writeShort(len);
writeBuffer.writeBytes(data);
return this;
}
public Serializer writeObject(Object object) {
if(object == null){
writeByte((byte)0);
}else{
if (object instanceof Integer) {
writeInt((int) object);
return this;
}
if (object instanceof Long) {
writeLong((long) object);
return this;
}
if (object instanceof Short) {
writeShort((short) object);
return this;
}
if (object instanceof Byte) {
writeByte((byte) object);
return this;
}
if (object instanceof String) {
String value = (String) object;
writeString(value);
return this;
}
if (object instanceof Serializer) {
writeByte((byte)1);
Serializer value = (Serializer) object;
value.writeToTargetBuff(writeBuffer);
return this;
}
throw new RuntimeException("不可序列化的类型:" + object.getClass());
}
return this;
}
private <T> boolean isEmpty(Collection<T> c) {
return c == null || c.size() == 0;
}
public <K,V> boolean isEmpty(Map<K,V> c) {
return c == null || c.size() == 0;
}
}
定义一个具体类来实现这个序列化接口。
package com.study;
import java.util.ArrayList;
import java.util.List;
import com.core.Serializer;
public class Player extends Serializer{
private long playerid;
private int age;
private List<Integer> skills = new ArrayList<>();
public long getPlayerid() {
return playerid;
}
public void setPlayerid(long playerid) {
this.playerid = playerid;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Integer> getSkills() {
return skills;
}
public void setSkills(List<Integer> skills) {
this.skills = skills;
}
@Override
protected void read() {
this.playerid = readLong();
this.age = readInt();
this.skills = readList(Integer.class);
}
// 序列化
@Override
protected void write() {
writeLong(playerid);
writeInt(age);
writeList(skills);
}
}
测试:
public static void main(String[] args) {
Player player = new Player();
player.setPlayerid(11111);
player.setAge(23);
player.getSkills().add(111);
byte[] bytes = player.getBytes();
System.out.println(Arrays.toString(bytes));
Player player2 = new Player();
player2.readFromBytes(bytes);
System.out.println(player2.getPlayerid() + "===" + player2.getAge());
}