Java NIO笔记(三):NIO Buffer(缓冲区)之进阶

        本节讲解NIO缓冲区(Buffer)比较底层的知识,虽然有的知识点实际用到的很少,但对理解Buffer也有一定的帮助。

        NIO缓冲区有八种缓冲区实现类,在文件IO、套接字(Socket)IO都得使用ByteBuffer来操作数据,可以说NIO中,ByteBuffer是非常核心和常用的缓冲区实现类,对ByteBuffer的实现由更深入的了解才能灵活正确的运用。

        字节(byte)是操作系统和所有I/O设备使用的基本数据类型,基本数据类型是供我们程序员来直接操作的,实际是以bit(比特位)存储在内存;那么1字节等于多少位呢?相信大家都应该知道等于八位。这里普及一下1byte等于8bit的背景,在计算机刚问世时,每个字节可以是3~12个比特位(bit),在市场的推动和前辈们的实践下,最终决定使用8位作为一个字节,因为8位足够表达英文字符集中任何一个字符,使用8位代表一个字节可以简化硬件设计,并且8位恰好可以容纳2个十六进制数字,所以8的倍数可以提供足够的组合来存储有效的数值;IBM在1960年率先推出的IBM360大型机使用的就是8位表示1字节。在这样的背景下,最终统一使用8比特位表示1字节。

一、字节顺序

        Java中有八种基本数据类型,其中除byte和boolean类型外的其他的基本数据都是由组合在一起的几个字节组成(byte是一个字节,boolean的值是true或false,而1字节的值范围是-128~127,boolean不能对应到一个或多个字节上),每个基本数据类型都是以连续字节顺序的形式存储在内存中,字节顺序分为:大端字节顺序小端字节顺序,什么是字节顺序?多字节的数值被存储在内存的方式就是字节顺序。数值的最高字节位于低位地址,系统使用的就是大端字节顺序;数值的最低字节位于低位地址,系统使用就是小端字节顺序。例如一个int类型的数值58700999,其十六进制表示为0x037fb4c7,内存图如下:


        网络协议(Internet Protocol,即IP)规定数据必须使用大端字节顺序传输,但是有硬件使用的是小端字节顺序,所以若本地系统是小端字节顺序,就需要将多字节数值先转换成大端字节顺序后才能正确传输数据。

        在Java NIO中使用ByteOrder类来封装字节顺序,使用ByteOrder.nativeOrder()可以获取本地系统的字节顺序;ByteOrder的toString()将返回BIG_ENDIAN(大端字节顺序)或LITTLE_ENDIAN(小端字节顺序)。ByteBuffer默认使用的是大端字节顺序,和本地系统字节顺序无关,其他所有的Buffer类使用的字节顺序都和本地系统的字节顺序一致。

        NIO中所有的缓冲区类都有order()方法,其返回ByteOrder对象,通过调用ByteOrder的toString()方法便可查看某个Buffer类的字节顺序。只有ByteBuffer才可以自定义设置字节顺序,通过调用ByteBuffer的order(ByteOrder bo)方法实现。

二、直接缓冲区

        直接缓冲区是不使用JVM堆栈而是通过操作系统来创建内存块用作缓冲区。所以可以使用操作系统底层I/O,其处理数据性能要高于基于JVM堆栈的非直接缓冲区;但是直接缓冲区的创建和销毁的性能开销要低于基于JVM堆栈的非直接缓冲区。

        NIO的八种缓冲区中,只有ByteBuffer才能创建直接缓冲区(还有MappedByteBuffer?MappedByteBuffer继承ByteBuffer),通过调用ByteBuffer.allocateDirect(int capacity)来创建直接缓冲区。

        所有的缓冲区类都可以通过调用isDirect()方法来判断是否是直接缓冲区。

三、视图缓冲区

        视图缓冲区就是新创建其他的基础数据类型缓冲区,新缓冲区和源缓冲区共享数据,但各自维护自己的属性(capacity、limit、position、mark)。

        只有ByteBuffer才能创建视图缓冲区,并且可以将缓冲区的数据转成。

        视图缓冲区是基础缓冲区的一部分,由基础缓冲区的position和limit限制。创建一个ByteBuffer的CharBuffer视图,如下图:

		ByteBuffer byteBuff = ByteBuffer.allocate(6);
		byteBuff.position(2);
		byteBuff.limit(4);
		System.out.println();
		CharBuffer charBuff = byteBuff.asCharBuffer();


  • asCharBuffer()
  • asShortBuffer()
  • asIntBuffer()
  • asLongBuffer()
  • asFloatBuffer()
  • asDoubleBuffer()

四、使用ByteBuffer提供的API直接存取基础数据

  • putInt(int value)
  • putChar(char value)
  • putLong(long value)
  • putDouble(double value)
  • putShort(short value)
  • putFloat(float value)
  • getInt()
  • ......

		ByteBuffer buff = ByteBuffer.allocate(100);
		buff.putShort((short)100);
		buff.putInt(200);
		buff.putLong(300L);
		buff.putFloat(400.5f);
		buff.putDouble(500.56);
		buff.putChar('A');
		buff.flip();
		buff.getShort();//return 100
		buff.getInt();//return 200
		buff.getLong();//return 300
		buff.getFloat();//return 400.5
		buff.getDouble();//return 500.56
		buff.getChar();//return 'A'


展开阅读全文

没有更多推荐了,返回首页