本文共 6522 字,大约阅读时间需要 21 分钟。
一:前期准备工作
1.要实现对象的序列化,先要了解一下java的8种基本数据类型及相关的储存字节大小
8中类型所占字节和位数如下:
类型 | 占用字节 | 占用位数 | 说明 |
byte | 1 | 8 | |
short | 2 | 16 | |
int | 4 | 32 | |
long | 8 | 64 | |
float | 4 | 32 | |
double | 8 | 64 | |
char | 2 | 16 | |
boolean | 1 | 8 | 实际上占用一个字节还是一个位,在或者是四个字节?
|
参阅:
是否通过验证方式:
1.通过查看生成class文件的内部结构来验证了 ,可以用jdk 自带的工具: javap -verbose TestBoolean -> NO:自码文件中的boolean 类型只是用Z来标注,而并没有转化成其它的数据类型
2,hexdump -C filename可以查看二进制文件 -> hexdump -C Test.class
下载 hexdump
二进制:
十进制:
十六进制: 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); }}
转载地址:http://iwadi.baihongyu.com/