怎样把byte数组转成string放到bytebuffer中 不用wrap方法

byte[] 数组转基础数据类型的问题 - ITeye问答
byte[] bata& = new byte[32];
问题:如何在这个数组中分断转化为我需要的数据类型。
例如:bata[0]至bata[8] 需要转化为long类型
&&&&& bata[9] 需要转化为int类型
&&&&& bata[10]转化为string类型
&&&&& bata[11]至bata[12]转化为double类型
希望各位走过路过不要错过,看看。帮忙解决下问题。。。
弄不好要加班。。。。
谢谢各位了!!!!
首先你要确定转换的rule是什么,每种类型多少位长,然后字节序是LITTLE-ENDIAN还是BIG-ENDIAN;字节序搞清楚是什么东西以后,怎么做位运算你也应该知道了吧
java.nio.ByteBuffer有byte[]与各基础类型的转换方法。
java.nio.charset.CharsetDecoder和java.nio.charset.CharsetEncoder有byte[]与char[]的转换方法。
走过路过不要错过~楼主卖的石榴还是红心果--!
一个long 8个字节,一个int 4个直接,楼主拿到的byte[]难道不是按照这个规则来的?
比较通用的做法是弄个实体类,里面按照byte[]需要转换的 顺序 定义字段以及类型
然后使用反射将byte[]的值取出来赋值给实体
如果不会用反射的话,就用笨办法将数据0-7取出来,然后转换成long,当然,字节序你必须要注意的
送你一个转换工具类,看能帮你什么忙不
public class FormatTransfer{
public static long byteArray2Long(byte[] a) {
long res = 0L;
int[] t = new int[8];
for (int i = 0; i & 8; i++) {
t[i] = a[7 - i];
res = t[0] & 0x0
for (int i = 1; i & 8; i++) {
res &&= 8;
res += (t[i] & 0x0ff);
public static long intArray2Long(int[] a) {
long res = 0L;
int[] t = new int[8];
for (int i = 0; i & 8; i++) {
t[i] = a[7 - i];
res = t[0] & 0x0
for (int i = 1; i & 8; i++) {
res &&= 8;
res += (t[i] & 0x0ff);
public static String getLocalhostip() {
InetAddress thisIp = InetAddress.getLocalHost();
return thisIp.getHostAddress();
} catch (Exception e) {
e.printStackTrace();
return "";
public static String longtoip(long longip) {
StringBuffer sb = new StringBuffer("");
sb.append(String.valueOf(longip &&& 24));// 直接右移24位
sb.append(".");
sb.append(String.valueOf((longip & 0x00ffffff) &&& 16)); // 将高8位置0,然后右移16位
sb.append(".");
sb.append(String.valueOf((longip & 0x0000ffff) &&& 8));
sb.append(".");
sb.append(String.valueOf(longip & 0x000000ff));
return sb.toString();
public static long iptolong(String strip) {
// int j = 0;
// int i = 0;
long[] ip = new long[4];
int position1 = strip.indexOf(".");
int position2 = strip.indexOf(".", position1 + 1);
int position3 = strip.indexOf(".", position2 + 1);
ip[0] = Long.parseLong(strip.substring(0, position1));
ip[1] = Long.parseLong(strip.substring(position1 + 1, position2));
ip[2] = Long.parseLong(strip.substring(position2 + 1, position3));
ip[3] = Long.parseLong(strip.substring(position3 + 1));
return (ip[0] && 24) + (ip[1] && 16) + (ip[2] && 8) + ip[3]; // ip1*256*256*256+ip2*256*256+ip3*256+ip4
* 将int转为低字节在前,高字节在后的byte数组
* @param n
* @return byte[]
public static byte[] toLH(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n && 8 & 0xff);
b[2] = (byte) (n && 16 & 0xff);
b[3] = (byte) (n && 24 & 0xff);
* 将int转为高字节在前,低字节在后的byte数组
* @param n
* @return byte[]
public static byte[] toHH(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n && 8 & 0xff);
b[1] = (byte) (n && 16 & 0xff);
b[0] = (byte) (n && 24 & 0xff);
* 将short转为低字节在前,高字节在后的byte数组
* @param n
* @return byte[]
public static byte[] toLH(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n && 8 & 0xff);
* 将short转为高字节在前,低字节在后的byte数组
* @param n
* @return byte[]
public static byte[] toHH(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n && 8 & 0xff);
* 将float转为低字节在前,高字节在后的byte数组
public static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
* 将float转为高字节在前,低字节在后的byte数组
public static byte[] toHH(float f) {
return toHH(Float.floatToRawIntBits(f));
* 将String转为byte数组
public static byte[] stringToBytes(String s, int length) {
while (s.getBytes().length & length) {
return s.getBytes();
* 将字节数组转换为String
* @param b
* @return String
public static String bytesToString(byte[] b) {
StringBuffer result = new StringBuffer("");
int length = b.
for (int i = 0; i & i++) {
result.append((char) (b[i] & 0xff));
return result.toString();
* 将字符串转换为byte数组
* @param s
* @return byte[]
public static byte[] stringToBytes(String s)
throws UnsupportedEncodingException {
return s.getBytes("GB2312");
* 将高字节数组转换为int
* @param b
* @return int
public static int hBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i & 3; i++) {
if (b[i] &= 0) {
s = s + b[i];
s = s + 256 + b[i];
s = s * 256;
if (b[3] &= 0) {
s = s + b[3];
s = s + 256 + b[3];
* 将低字节数组转换为int
* @param b
* @return int
public static int lBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i & 3; i++) {
if (b[3 - i] &= 0) {
s = s + b[3 - i];
s = s + 256 + b[3 - i];
s = s * 256;
if (b[0] &= 0) {
s = s + b[0];
s = s + 256 + b[0];
* 将低字节数组转换为int
* @param b
* @return int
public static int lBytesToInt(int[] b) {
int s = 0;
for (int i = 0; i & 3; i++) {
if (b[3 - i] &= 0) {
s = s + b[3 - i];
s = s + 256 + b[3 - i];
s = s * 256;
if (b[0] &= 0) {
s = s + b[0];
s = s + 256 + b[0];
* 高字节数组到short的转换
* @param b
* @return short
public static short hBytesToShort(byte[] b) {
int s = 0;
if (b[0] &= 0) {
s = s + b[0];
s = s + 256 + b[0];
s = s * 256;
if (b[1] &= 0) {
s = s + b[1];
s = s + 256 + b[1];
short result = (short)
* 低字节数组到short的转换
* @param b
* @return short
public static short lBytesToShort(byte[] b) {
int s = 0;
if (b[1] &= 0) {
s = s + b[1];
s = s + 256 + b[1];
s = s * 256;
if (b[0] &= 0) {
s = s + b[0];
s = s + 256 + b[0];
short result = (short)
* 低字节数组到short的转换
* @param b
* @return short
public static short lBytesToShort(int[] b) {
int s = 0;
if (b[1] &= 0) {
s = s + b[1];
s = s + 256 + b[1];
s = s * 256;
if (b[0] &= 0) {
s = s + b[0];
s = s + 256 + b[0];
short result = (short)
* 高字节数组转换为float
* @param b
* @return float
@SuppressWarnings("static-access")
public static float hBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[0] & 0xff) && 8 | (b[1] & 0xff)) && 8) | (b[2] & 0xff)) && 8
| (b[3] & 0xff);
return F.intBitsToFloat(i);
* 低字节数组转换为float
* @param b
* @return float
@SuppressWarnings("static-access")
public static float lBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[3] & 0xff) && 8 | (b[2] & 0xff)) && 8) | (b[1] & 0xff)) && 8
| (b[0] & 0xff);
return F.intBitsToFloat(i);
* 低字节数组转换为float
* @param b
* @return float
@SuppressWarnings("static-access")
public static float lBytesToFloat(int[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[3] & 0xff) && 8 | (b[2] & 0xff)) && 8) | (b[1] & 0xff)) && 8
| (b[0] & 0xff);
return F.intBitsToFloat(i);
* 将byte数组中的元素倒序排列
public static byte[] bytesReverseOrder(byte[] b) {
int length = b.
byte[] result = new byte[length];
for (int i = 0; i & i++) {
result[length - i - 1] = b[i];
* 打印byte数组
public static void printBytes(byte[] bb) {
int length = bb.
for (int i = 0; i & i++) {
System.out.print(bb + " ");
System.out.println("");
public static void logBytes(byte[] bb) {
int length = bb.
String out = "";
for (int i = 0; i & i++) {
out = out + bb + " ";
* 将int类型的值转换为字节序颠倒过来对应的int值
* @param i
* @return int
public static int reverseInt(int i) {
int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
* 将short类型的值转换为字节序颠倒过来对应的short值
* @param s
* @return short
public static short reverseShort(short s) {
short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
* 将float类型的值转换为字节序颠倒过来对应的float值
* @param f
* @return float
public static float reverseFloat(float f) {
float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
* 此方法将参数i 转换为 num bytes的byte 数组 (小端模式)
* @param i
* @param num
public static byte[] int2Array(Long i, int num) {
byte[] a = new byte[num];
for (int j = 0; j & a. j++) {
a[j] = (byte) (i & 0xff);
byte[] cc = new byte[a.length];
for (int x = 0; x & a. x++) {
cc[x] = a[x];
你是要做流解析吧!
这个必须做到指定字节长度是指定的类型,否则无法解析!
我想你应该为你的系统做一个约定,例如int就是4个字节!
然后在每个数据前面增加一个数据类型字节!这样你的一个int型数据就需要5个字节!
例如解析到byte[0]是 0 ,那么就截取4后面四个字节,然后当成int来解析即可!
详细到博客咨询!
已解决问题
未解决问题byte输出简单解决方法
现在有一段程序,大概是这样的:
对输入的字符串str处理:byte[] bb = str.getBytes(),获得的字节数组存进一个ByteBuffer。另有一个线程不定期地从Bytebuffer里取出长度不定的字节,打包后由信号传输设备传输到另一台电脑,收到包后再解析。
现在的问题是对英文字符串处理没问题,但中文的不定期出乱码。我觉得是编码的问题。用GB2312编码,getBytes()处理后英文字符对应一个字节,中文的是两个。放到ByteBuffer里后,截取时可能刚好把中文的两个字节分开到两个包里了。因为传输后对每个包的解析是单独进行的,直接处理,没有再把字节取出来缓存后再处理,所以会出现乱码。
所以我的想法是,能不能判断ByteButter里我要截取的字节数组末尾的那个字节是英文的还是中文的字符产生的。是英文的我就不处理,是中文的就分情况处理。
哪位能给我想个办法,谢谢~
我简单做了一个。。用GBK字符库的char[],代替byte[]
public class strdeal {
public String &getString(){//输入字符串
System.out.println(&input string&);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String s=&&;
s = br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//System.out.println(s);//可以直接打印字符串
public byte[] getByet(String s){//字符串转为byte[]
byte[] bb = s.getBytes();
private char[] getChars (byte[] bytes) {//byte转为char[],使用GBK
& & &Charset cs = Charset.forName (&GBK&);
& & &ByteBuffer bb = ByteBuffer.allocate (bytes.length);
& & &bb.put (bytes);
& & & & & & & & bb.flip ();
& & & CharBuffer cb = cs.decode (bb);
& return cb.array();
public static void main(String args[]){//简单测试
strdeal sdeal=new strdeal();
//System.out.println(sdeal.getString());
byte[] arrbyte=sdeal.getByet(sdeal.getString());
char[] arrchar=sdeal.getChars(arrbyte);
/*for(byte b:arrbyte){
System.out.print(b);
for(char c:arrchar){
System.out.print(c);
System.out.println();
String res=new String(arrbyte);
System.out.println(res);
input string
ABC124不是么
ABC124不是么
阅读本文后您有什么感想? 已有
人给出评价!
04-10-0804-10-0804-10-0804-10-0704-10-0704-10-0704-10-0704-10-07
注:您的评论需要经过审核才会显示出来
Copyright &
PC6下载().All Rights Reserved
备案编号:湘ICP备号【已解决】Android中byte数组byte[]实现如何拷贝
android中有两个buffer,想要实现拷贝:
void xxx(byte[] buffer, int writeLength){
final byte[] tmpBuf = new byte[writeLength];
想要把buffer中长度writeLength拷贝到新的tmpBuf中。
【解决过程】
1.网上搜了:
android byte buffer copy
结果很是失望:
java中竟然没有方便好用的,直接实现byte数组拷贝的函数。。。
2.试试那个System.arraycopy:
final byte[] tmpBuf = new byte[writeLength];
System.arraycopy(buffer, 0, tmpBuf, 0, writeLength);
是可以的:
java中,实现byte[]的拷贝,可以用
System.arraycopy
共享此文章:
分类 未分类
免费的格式化Javascript源码的网站
查询Unicode字符,且还带Oct,Decimal,Hex,HTML Entity
HTML和Javascript都支持,很好用。Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。
这篇文章主要介绍了Android在JNI中使用ByteBuffer的方法,涉及Android中缓冲区的相关使用技巧,需要的朋友可以参考下
本文实例讲述了Android在JNI中使用ByteBuffer的方法。分享给大家供大家参考。具体如下:
一、ByteBuffer 定义
在NIO中,数据的读写操作始终是与缓冲区相关联的(读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区)
缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型。ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer。
ByteBuffer有以下几种常见属性:
mark:初始值为-1,标记索引地点;
position:初始值为0,索引下标;
limit:最好定义成bytebuffer的长度,即允许可读空间长度;
capacity:缓冲区能容纳的数据元素的最大数量,创建之后无法被改变;
二、ByteBuffer使用
1. 创建ByteBuffer
① 使用allocate()创建:
ByteBuffer buf = ByteBuffer.allocate(length);
//length表示buf的长度
② 使用数组创建:
ByteBuffer buf = ByteBuffer.wrap(byteArray);
//byteArray表示一个数组
2. 回绕缓冲区
buf.flip();
这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取。
3. 清除缓冲区
buf.clear();
这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区。
4. ByteBuffer与byte[]交互
byte[] bytearray = new byte[10];
ByteBuffer buf = ByteBuffer.wrap(bytearray);
//将数组写入buf
bytearray = new byte[buf.remaining()];
buf.get(bytearray,0,bytearray.length());
//将数据读到数组中
bytearray = new byte[buf.capacity()];
三、ByteBuffer与JNI交互
在Java1.4版本中引入的JNI有三个函数可以用于NIO的直接缓冲器。一个直接字节缓冲器是一个用于字节数据的容器,Java将尽力在它上面执行本机I/O操作。JNI定义了三个用于NIO操作的函数。
基于到存储器地址的指针以及存储器长度(容量),函数分配并且返回一个新的Java.nio.ByteBuffer。如果函数没有针对当前Java虚拟机实现,则返回NULL,或者抛出一个异常。如果没有存储器可用,则将会抛出一个OutOfMemoryException。
jobject NewDirectByteBuffer(void* address, jlong capacity);
GetDirectBufferAddress函数返回一个指向被传入的java.nio.ByteBuffer对象的地址指针。如果函数尚未针对当前虚拟机实现,或者如果buf不是java.nio.ByteBuffer的一个对象,又或者存储器区尚未定义,则都将返回NULL。
void* GetDirectBufferAddress(jobject buf);
GetDirectBufferCapacity函数返回被传入的java.nio.ByteBuffer对象的容量(以字节计数)。如果函数没有针对当前环境实现,或者如果buf不是java.nio.ByteBuffer类型的对象返回-1。
jlong GetDirectBufferCapacity(jobject buf);
1. Jni中调用
public final int processData(ByteBuffer data);
Native 接口:
private native long native_Process(ByteBuffer data);
static jlong native_Process(JNIEnv *env,jobject obj,jobject data);
注意ByteBuffer在JNI层中的签名:Ljava/nio/ByteB
2. 示例(C++):
jclass cls = env-&GetObjectClass(obj);
jfieldID fid = env-&GetFieldID(cls, "data","Ljava/nio/ByteB");
jobject bar = env-&GetObjectField(obj, fid);
pImageData-&data= (MByte*)env-&GetDirectBufferAddress(bar);
//data是结构体pImageData中的byte[];
希望本文所述对大家的Android程序设计有所帮助。
Copyright &
All Rights Reserved &&&&&&1306人阅读
在NIO中,数据的读写操作始终是与缓冲区相关联的.读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区.缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型.ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer.因此ByteBuffer的用法是有必要牢固掌握的.
1.创建ByteBuffer
1.1 使用allocate()静态方法
&&& ByteBuffer buffer=ByteBuffer.allocate(256);
&&& 以上方法将创建一个容量为256字节的ByteBuffer,如果发现创建的缓冲区容量太小,唯一的选择就是重新创建一个大小合适的缓冲区.
1.2 通过包装一个已有的数组来创建
&&& 如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.
&&& ByteBuffer buffer=ByteBuffer.wrap(byteArray);
&&& 如果要将一个字符串存入ByteBuffer,可以如下操作:
&&& String sendString=&你好,服务器. &;
&&& ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes(&UTF-16&));
2.回绕缓冲区
& buffer.flip();
& 这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取.
3.清除缓冲区
& buffer.clear();
& 这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区.
4.从套接字通道(信道)读取数据
& int bytesReaded=socketChannel.read(buffer);
& 执行以上方法后,通道会从socket读取的数据填充此缓冲区,它返回成功读取并存储在缓冲区的字节数.在默认情况下,这至少会读取一个字节,或者返回-1指示数据结束.
5.向套接字通道(信道)写入数据
& socketChannel.write(buffer);
& 此方法以一个ByteBuffer为参数,试图将该缓冲区中剩余的字节写入信道.
-----------------------
ByteBuffer俗称缓冲器, 是将数据移进移出通道的唯一方式,并且我们只能创建一个独立的基本类型缓冲器,或者使用“as”方法从 ByteBuffer 中获得。ByteBuffer&中存放的是字节,如果要将它们转换成字符串则需要使用&Charset&,&Charset&是字符编码,它提供了把字节流转换成字符串&(&解码&)&和将字符串转换成字节流&(&编码)&的方法。
private byte[] getBytes (char[] chars) {//将字符转为字节(编码)
&&&Charset cs = Charset.forName (&UTF-8&);
&&&CharBuffer cb = CharBuffer.allocate (chars.length);
&&&cb.put (chars);
&&&cb.flip ();
&&&ByteBuffer bb = cs.encode (cb)
&&&return bb.array();
&&&&&&&&&}
private char[] getChars (byte[] bytes) {//将字节转为字符(解码)
&&&&&&Charset cs = Charset.forName (&UTF-8&);
&&&&&&ByteBuffer bb = ByteBuffer.allocate (bytes.length);
&&&&&&bb.put (bytes);
&&&&&&bb.flip ();
&&&&&&&CharBuffer cb = cs.decode (bb);
&&&return cb.array();
通道也就是FileChannel,可以由FileInputStream,FileOutputStream,RandomAccessFile三个类来产生,例如:FileChannel fc = new FileInputStream().getChannel();与通道交互的一般方式就是使用缓冲器,可以把通道比如为煤矿(数据区),而把缓冲器比如为运煤车,想要得到煤一般都通过运煤车来获取,而不是直接和煤矿取煤。用户想得到数据需要经过几个步骤:
一、用户与ByteBuffer的交互
&&&&向ByteBuffer中输入数据,有两种方式但都必须先为ByteBuffer指定容量
&&&&&&&&&ByteBuffer buff = ByteBuffer.allocate(BSIZE);
&&&&&a)&&buff&&= &ByteBuffer.wrap(&askjfasjkf&.getBytes())注意:wrap方法是静态函数且只能接收byte类型的数据,任何其他类型的数据想通过这种方式传递,需要进行类型的转换。
&&&&&b)&&buff.put();可以根据数据类型做相应调整,如buff.putChar(chars),buff.putDouble(double)等
二、FileChannel 与 ByteBuffer的交互:
&&&&缓冲器向通道输入数据
&&&&&FileChannel fc = new&FileInputStream().getChannel();&&
&&&&&fc.write(buff);
&&&&&fc.close();
三、&用户与ByteBuffer交互
&&&&通道向缓冲器送入数据
&&&&FileChannel fc =&&new FileOutputStream().getChannel();
&&&&fc.read(&buff);
&&&&fc.flip();
四、呈现给用户(三种方式)
&&1)String encoding = System.getProperty(&file.encoding&);
&&&System.out.println(&Decoded using & + encoding + &: &&&+ Charset.forName(encoding).decode(buff));&&&
&&2)System.out.println(buff.asCharBuffer());//这种输出时,需要在输入时就进行编码getBytes(&UTF-8&)
&&3) System.out.println(buff.asCharBuffer());//通过CharBuffer向ByteBuffer输入 buff.asCharBuffer().put。
fc.rewind();
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
类ByteBuffer是Java nio程序经常会用到的类,也是重要类 ,我们通过源码分析该类的实现原理。
一.ByteBuffer类的继承结构
public abstract class ByteBuffer
extends Buffer
implements Comparable&ByteBuffer&
ByteBuffer的核心特性来自Buffer
二. ByteBuffer和Buffer的核心特性
A container for data of a specific primitive type. 用于特定基本类型数据的容器。
子类ByteBuffer支持除boolean类型以外的全部基本数据类型。
补充,回顾Java的基本数据类型
Java语言提供了八种基本类型,六种数字类型(四个整数型,两个浮点型),一种字符类型,一种布尔型。
1、整数:包括int,short,byte,long
2、浮点型:float,double
3、字符:char
4、布尔:boolean
类型&&& 大小&最小值&& 最大值
byte&&& 8-bit&-128&& +127
short&&16-bit&-2^15&& +2^15-1
int&&&&&& 32-bit&-2^31&& +2^31-1
long&&& 64-bit&-2^63&& +2^63-1
float&&& 32-bit&IEEE754&& IEEE754
double&64-bit&IEEE754&& IEEE754
char&&& 16-bit&Unicode 0&Unicode 2^16-1
boolean&-----&-----&& ------ & & 
本质上,Buffer也就是由装有特定基本类型数据的一块内存缓冲区和操作数据的4个指针变量(mark标记,position位置, limit界限,capacity容量)组成。不多说,上源码:
Java代码 &
public&abstract&class&Buffer&{&&&&&&&&&&&&&&private&int&mark&=&-1;&&&&&&private&int&position&=&0;&&&&&&private&int&&&&&&&private&int&&&&&&&......&&}&&&&public&abstract&class&ByteBuffer&&&&&&extends&Buffer&&&&&&implements&Comparable&ByteBuffer&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&final&byte[]&&&&&&&&&&final&int&&&&&&&boolean&isReadO&&&&&&&&&......&&}&&
&其中,字节数组final byte[] hb就是所指的那块内存缓冲区。
Buffer缓冲区的主要功能特性有:
a.Transferring data& 数据传输,主要指可通过get()方法和put()方法向缓冲区存取数据,ByteBuffer提供存取除boolean以为的全部基本类型数据的方法。
b.Marking and resetting& 做标记和重置,指mark()方法和reset()方法;而标记,无非是保存操作中某个时刻的索引位置。
c.Invariants 各种指针变量
d.Clearing, flipping, and rewinding 清除数据,位置(position)置0(界限limit为当前位置),位置(position)置0(界限limit不变),指clear()方法, flip()方法和rewind()方法。
e.Read-only buffers 只读缓冲区,指可将缓冲区设为只读。
f.Thread safety 关于线程安全,指该缓冲区不是线程安全的,若多线程操作该缓冲区,则应通过同步来控制对该缓冲区的访问。
g.Invocation chaining 调用链, 指该类的方法返回调用它们的缓冲区,因此,可将方法调用组成一个链;例如:
&b.flip();
&b.position(23);
&b.limit(42);
&b.flip().position(23).limit(42);
三.ByteBuffer的结构
ByteBuffer主要由是由装数据的内存缓冲区和操作数据的4个指针变量(mark标记,position位置, limit界限,capacity容量)组成。
内存缓冲区:字节数组final byte[] hb;
ByteBuffer的主要功能也是由这两部分配合实现的,如put()方法,就是向数组byte[] hb存放数据。
Java代码 &
ByteBuffer&bb&=&ByteBuffer.allocate(10);&&&&&bb.put((byte)9);&&
底层源码的实现如下
Java代码 &
class&HeapByteBuffer&&&&&&extends&ByteBuffer&&{&&&&&&......&&&&&&public&ByteBuffer&put(byte&x)&{&&&&&&&&hb[ix(nextPutIndex())]&=&x;&&&&&&&&return&this;&&&&&&}&&&&&&&&&&&&......&&&&&&final&int&nextPutIndex()&{&&&&&&&&&&&&if&(position&&=&limit)&&&&&&&&throw&new&BufferOverflowException();&&&&&&&&&return&position++;&&&&&&}&&&&&&......&&}&&
如上所述,bb.put((byte)9);执行时,先判断position 是否超过 limit,否则指针position向前移一位,将字节(byte)9存入position所指byte[] hb索引位置。
get()方法相似;
Java代码 &
public&byte&get()&{&&&&&return&hb[ix(nextGetIndex())];&&}&&
4个指针的涵义
position:位置指针。微观上,指向底层字节数组byte[] hb的某个索引位置;宏观上,是ByteBuffer的操作位置,如get()完成后,position指向当前(取出)元素的下一位,put()方法执行完成后,position指向当前(存入)元素的下一位;它是核心位置指针。
mark标记:保存某个时刻的position指针的值,通过调用mark()实现;当mark被置为负值时,表示废弃标记。
capacity容量:表示ByteBuffer的总长度/总容量,也即底层字节数组byte[] hb的容量,一般不可变,用于读取。
limit界限:也是位置指针,表示待操作数据的界限,它总是和读取或存入操作相关联,limit指针可以被& 改变,可以认为limit&=capacity。
& ByteBuffer结构如下图所示
四.&ByteBuffer的关键方法实现
&&1.取元素
Java代码 &
public&abstract&byte&get();&&&&&&public&byte&get()&{&&&&&return&hb[ix(nextGetIndex())];&&}&&&&&&&&final&int&nextGetIndex()&{&&&&&&&&&&&&&&&&&&&&if&(position&&=&limit)&&&throw&new&BufferUnderflowException();&&&&&return&position++;&&}&&&
&&2.存元素
Java代码 &
public&abstract&ByteBuffer&put(byte&b);&&&&&&&&public&ByteBuffer&put(byte&x)&{&&&&&&&hb[ix(nextPutIndex())]&=&x;&&&&&&&return&this;&&&}&&
&&3.清除数据&&&
Java代码 &
public&final&Buffer&clear()&{&&&&&&position&=&0;&&&&&&limit&=&&&&&&&mark&=&-1;&&&&&&return&this;&&}&&
&&& 可见,对于clear()方法,ByteBuffer只是重置position指针和limit指针,废弃mark标记,并没有真正清空缓冲区/底层字节数组byte[] hb的数据;
&&& ByteBuffer也没有提供真正清空缓冲区数据的接口,数据总是被覆盖而不是清空。
&&& 例如,对于Socket读操作,若从socket中read到数据后,需要从头开始存放到缓冲区,而不是从上次的位置开始继续/连续存放,则需要clear(),重置position指针,但此时需要注意,若read到的数据没有填满缓冲区,则socket的read完成后,不能使用array()方法取出缓冲区的数据,因为array()返回的是整个缓冲区的数据,而不是上次read到的数据。
&&4. 以字节数组形式返回整个缓冲区的数据/byte[] hb的数据
Java代码 &
public&final&byte[]&array()&{&&&&&&if&(hb&==&null)&&&throw&new&UnsupportedOperationException();&&&&&&&if&(isReadOnly)&&&&&&&&&&throw&new&ReadOnlyBufferException();&&&&&&&return&&&}&&
&&5.flip-位置重置
Java代码 &
public&final&Buffer&flip()&{&&&&&&limit&=&&&&&&&position&=&0;&&&&&&mark&=&-1;&&&&&&return&this;&&}&&
&&& socket的read操作完成后,若需要write刚才read到的数据,则需要在write执行前执行flip(),以重置操作位置指针,保存操作数据的界限,保证write数据准确。&&&
&6.rewind-位置重置
Java代码 &
public&final&Buffer&rewind()&{&&&&&&&position&=&0;&&&&&&&mark&=&-1;&&&&&&&return&this;&&}&&
&& Rewinds this buffer. The position is set to zero and the mark is discarded.
& 和flip()相比较而言,没有执行limit =
7.判断剩余的操作数据或者剩余的操作空间
Java代码 &
public&final&int&remaining()&{&&&&&&return&limit&-&&&}&&
&& 常用于判断socket的write操作中未写出的数据;
Java代码 &
public&final&Buffer&mark()&{&&&&&&mark&=&&&&&&&return&this;&&}&&
& 9.重置到标记
Java代码 &
public&final&Buffer&reset()&{&&&&&&int&m&=&&&&&&&if&(m&&&0)&&&&&&&&throw&new&InvalidMarkException();&&&&&&position&=&m;&&&&&&return&this;&&}&&
五.创建ByteBuffer对象的方式
&& 1.allocate方式
Java代码 &
public&static&ByteBuffer&allocate(int&capacity)&{&&&&if&(capacity&&&0)&&&&&&&&throw&new&IllegalArgumentException();&&&&&&&&return&new&HeapByteBuffer(capacity,&capacity);&&}&&&&HeapByteBuffer(int&cap,&int&lim)&{&&&&&&&&&super(-1,&0,&lim,&cap,&new&byte[cap],&0);&&&&&&&&&&&&}&&&&&&&&&&&&ByteBuffer(int&mark,&int&pos,&int&lim,&int&cap,&&&&&&&&&&&byte[]&hb,&int&offset)&&{&&&&super(mark,&pos,&lim,&cap);&&&&this.hb&=&&&&&this.offset&=&&&}&&&&&&&&&&&&Buffer(int&mark,&int&pos,&int&lim,&int&cap)&{&&&&&&&if&(cap&&&0)&&&&&&&&throw&new&IllegalArgumentException();&&&&&&&this.capacity&=&&&&&&&&limit(lim);&&&&&&&position(pos);&&&&&&&if&(mark&&=&0)&{&&&&&&&&&if&(mark&&&pos)&&&&&&&&&&&&throw&new&IllegalArgumentException();&&&&&&&&&this.mark&=&&&&&&&&}&&&}&&p;&&
&&& 由此可见,allocate方式创建ByteBuffer对象的主要工作包括: 新建底层字节数组byte[] hb(长度为capacity),mark置为-1,position置为0,limit置为capacity,capacity为用户指定的长度。
&& 2.wrap方式
Java代码 &
public&static&ByteBuffer&wrap(byte[]&array)&{&&return&wrap(array,&0,&array.length);&&&&&}&&&&&&&&&public&static&ByteBuffer&wrap(byte[]&array,&&&&&&&&&&&&&&&&&&int&offset,&int&length)&&&&&{&&&&&&&&&try&{&&&&&&&&&&&&return&new&HeapByteBuffer(array,&offset,&length);&&&&&&&&&}&catch&(IllegalArgumentException&x)&{&&&&&&&&&&&&throw&new&IndexOutOfBoundsException();&&&&&&&&&}&&&&&}&&&&&&&HeapByteBuffer(byte[]&buf,&int&off,&int&len)&{&&&&&&&&&&&super(-1,&off,&off&+&len,&buf.length,&buf,&0);&&&&&&&&&&&&&&&&&&}&&
&& wrap方式和allocate方式本质相同,不过因为由用户指定的参数不同,参数为byte[] array,所以不需要新建字节数组,byte[] hb置为byte[] array,mark置为-1,position置为0,limit置为array.length,capacity置为array.length。
&&&&&& 六、结论
&&&&&&& 由此可见,ByteBuffer的底层结构清晰,不复杂,源码仍是弄清原理的最佳文档。
读完此文,应该当Java nio的SocketChannel进行read或者write操作时,ByteBuffer的四个指针如何移动有了清晰的认识。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:19909次
排名:千里之外
原创:31篇
(1)(3)(6)(4)(5)(13)(3)

我要回帖

更多关于 byte数组转成string 的文章

 

随机推荐