Netty3 - 自定义序列化协议(1)

一:前期准备工作

1.要实现对象的序列化,先要了解一下java的8种基本数据类型及相关的储存字节大小

8中类型所占字节和位数如下:

类型占用字节 占用位数说明
byte    18 
short    216 
int    432 
long    864 
float    432 
double 864 
char216 
boolean18

实际上占用一个字节还是一个位,在或者是四个字节?

 

 

 

 

 

 

 

 

 

 

 

参阅:

https://blog.csdn.net/YuanMxy/article/details/74170745

是否通过验证方式:

1.通过查看生成class文件的内部结构来验证了 ,可以用jdk 自带的工具: javap -verbose TestBoolean -> NO:自码文件中的boolean 类型只是用Z来标注,而并没有转化成其它的数据类型

2,hexdump -C filename可以查看二进制文件  ->  hexdump -C Test.class  

下载 hexdump https://www.di-mgt.com.au/hexdump-for-windows.html

二进制:

十进制:

十六进制: 0x就是代表十六进制,0x00 - 0xFF 

对于二进制来说,8位二进制我们称之为一个字节,二进制的表达范围值是从0b00000000~0b11111111,
而我们程序中用十六进制表示的时候就是从0x00到0xFF,这里教大家一个二进制转换十进制和十六进制的方法,
二进制4位一组,遵循8,4,2,1的规律比如 1010,那么从最高位开始算,数字大小是8*1+4*0+2*1+1*0 = 10,
那么十进制就是10,十六进制就是0xA。尤其二进制转十六进制的时候,十六进制一位刚好是和二进制的4位相互对应的

2.负数在计算机内是如何表示的

原码:

反码:

补码:

 

3.字节序列化模式:大端模式与小端模式

大端模式:高位在前

小端模式:低位在前

示例:

/**
 * 以大端模式将int转成byte[]
 */
public static byte[] intToBytesBig(int value) {
    byte[] src = new byte[4];
    src[0] = (byte) ((value >> 24) & 0xFF);
    src[1] = (byte) ((value >> 16) & 0xFF);
    src[2] = (byte) ((value >> 8) & 0xFF);
    src[3] = (byte) (value & 0xFF);
    return src;
}

/**
 * 以小端模式将int转成byte[]
 *
 * @param value
 * @return
 */
public static byte[] intToBytesLittle(int value) {
    byte[] src = new byte[4];
    src[3] = (byte) ((value >> 24) & 0xFF);
    src[2] = (byte) ((value >> 16) & 0xFF);
    src[1] = (byte) ((value >> 8) & 0xFF);
    src[0] = (byte) (value & 0xFF);
    return src;
}

/**
 * 以大端模式将byte[]转成int
 */
public static int bytesToIntBig(byte[] src, int offset) {
    int value;
    value = (int) (((src[offset] & 0xFF) << 24)
            | ((src[offset + 1] & 0xFF) << 16)
            | ((src[offset + 2] & 0xFF) << 8)
            | (src[offset + 3] & 0xFF));
    return value;
}

/**
 * 以小端模式将byte[]转成int
 */
public static int bytesToIntLittle(byte[] src, int offset) {
    int value;
    value = (int) ((src[offset] & 0xFF)
            | ((src[offset + 1] & 0xFF) << 8)
            | ((src[offset + 2] & 0xFF) << 16)
            | ((src[offset + 3] & 0xFF) << 24));
    return value;
}

 

二:基本数据类型的序列化操作

查看示例代码

package custserialize;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;

/**
 * 基本数据类型是如何序列化的
 *  首先也就是要确定基本数据类型是如何转化成字节的。通常有两种方式
 *  大端:高位在前
 *  小端:低位在前
 */
public class TypeSerialize {
    public static void main(String[] args) throws Exception{
        short age=120;
        int sales=123456;
        //1:字节输出流
        System.out.println("************************JDK api*******************************");
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        outputStream.write(shortToBytes(age));
        outputStream.write(intToBytes(sales));
        byte[] bytes=outputStream.toByteArray();
        System.out.println("result bytes="+Arrays.toString(bytes));
        //解析,按照写入的顺序读出相应的字节大小
        ByteArrayInputStream inputStream=new ByteArrayInputStream(bytes);
        byte[] ageByte=new byte[2];
        byte[] saleByte=new byte[4];
        inputStream.read(ageByte);
        inputStream.read(saleByte);
        System.out.println("age="+bytesToShort(ageByte));
        System.out.println("sales="+bytesToInt(saleByte));//bytesToInt bytes2Int

        //2.Nio的ByteBuffer,缺点就是必须先确定要分配的字节数组的大小,不能动态的进行扩容
        System.out.println("**********************JDK NIO Api**************************************");
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.putInt(sales);
        byte[] b1=buffer.array();
        System.out.println("int byte="+Arrays.toString(b1));
        System.out.println("reback ="+bytes2Int(b1));

        //3.Netty中提供的ChannelBuffer
        System.out.println("****************************Netty Api************************************");
        ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
        channelBuffer.writeInt(10101);
        channelBuffer.writeFloat(9999.99f);
        channelBuffer.writeChar('A');
        byte[] channelBufferBytes=new byte[channelBuffer.writerIndex()];//channelbuffer 写的位置
        channelBuffer.readBytes(channelBufferBytes);
        System.out.println("channel buffer bytes="+Arrays.toString(channelBufferBytes));
        ChannelBuffer readChannelBuffer=ChannelBuffers.wrappedBuffer(channelBufferBytes);
        System.out.println("netty int="+readChannelBuffer.readInt());
        System.out.println("netty float="+readChannelBuffer.readFloat());
        System.out.println("netty char="+readChannelBuffer.readChar());



    }

    /**
     * 采用大端字节序列(即是先写高位,在写低位)
     *  返回的字节数组中,byte[0]对应的是原数据位表示的最高位
     * @param param
     * @return
     */
    public static  byte[] shortToBytes(short param){
        // short 在jdk的规范说明中占用2个字节
        byte[] bytes=new byte[2];
        bytes[0]=(byte)(param >> 1*8);
        bytes[1]=(byte)(param >> 0*8);
        return bytes;
    }

    /**
         * 采用大端字节序列(即是先写高位,在写低位)
     * 返回的字节数组中,byte[0]对应的是原数据位表示的最高位
     * @param bytes
     * @return
     */
    public static short bytesToShort(byte[] bytes){
        short result=(short)( (bytes[0] << 1*8 )   // 第一痊为高位
                |
                (bytes[1] << 0*8)
        );
        return result;
    }

    /**
     * 将int 类型转化为字节数组
     * @param param
     * @return
     */
    public static byte[] intToBytes(int param){
        byte[] fbyte=new byte[4];//int 占用四个字节
        fbyte[0] = (byte)(param >> 3*8);
        fbyte[1] = (byte)(param >> 2*8);
        fbyte[2] = (byte)(param >> 1*8);
        fbyte[3] = (byte)(param >> 0*8);
        return fbyte;
    }

    /**
     *
     * @param bytes
     * @return
     */
    public static int bytesToInt(byte[] bytes){
        return ( (bytes[0] & 0xFF) << 3*8) |
                ( (bytes[1]  & 0xFF)<< 2*8) |
                ( (bytes[2]  & 0xFF) << 1*8) |
                ( (bytes[3]  & 0xFF) << 0*8);
    }


    /*****************************************************/
    /**
     * 大端方式
     * @param bytes
     * @return
     */
    private static int bytes2Int(byte[] bytes) {
        int addr;
        if (bytes.length == 1) {
            addr = bytes[0] & 0xFF;
        } else {
            addr = bytes[0] & 0xFF;
            addr = (addr << 8) | (bytes[1] & 0xff);
            addr = (addr << 8) | (bytes[2] & 0xff);
            addr = (addr << 8) | (bytes[3] & 0xff);
        }
        return addr;
    }

    /**
     * 大端方式
     * @param bytes 数组大端
     * @return float
     */
    private float bytes2Float(byte[] bytes) {
        int l;
        l = bytes[0];
        l &= 0xff;
        l |= ((long) bytes[1] << 8);
        l &= 0xffff;
        l |= ((long) bytes[2] << 16);
        l &= 0xffffff;
        l |= ((long) bytes[3] << 24);
        return Float.intBitsToFloat(l);
    }

}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值