Java中byte使用注意事项

目前在做的SYSC 3303 Project是关于使用Java编写TFTP服务器/客户端。其中Java的发送数据包要用byte数组。凭着C语言的扎实基础,想当然的认为byte就是8位无符号整数。于是每一个数据包都由String转为byte发送。

但是,问题出现了。在发送ACK和DATA包时,传出的Block #有一部分不正确(例如:65535)。调试的时候显示在创建数据包的时候数据为0xFF_0xFF(65535),但是接收到的数据为0x3F_0x3F(16191)。

看了一下Java Specification,发现在Java中byte和int都是带符号的整数(signed integer),而且唯一的无符号整数(unsigned integer)是char。再往下看,原来char是按照UTF-16编码储存的(16位无符号整数)。郁闷啊。

接下来的工作就是查怎样从byte转换到int。因为带符号整数都是要做带符号扩展(signed extend),也就是说值为0xFF的byte在转成int之后,值为0xFFFFFFFF。终于在网上查到byte与int无符号转换方法,如下:

[code lang="java"]
int firstByte = 0;
int secondByte = 0;
int thirdByte = 0;
int fourthByte = 0;

firstByte = (0x000000FF & ((int)buf[index]));
secondByte = (0x000000FF & ((int)buf[index+1]));
thirdByte = (0x000000FF & ((int)buf[index+2]));
fourthByte = (0x000000FF & ((int)buf[index+3]));

long anUnsignedInt = 0;

buf[0] = (anUnsignedInt & 0xFF000000L) >> 24;
buf[1] = (anUnsignedInt & 0x00FF0000L) >> 16;
buf[2] = (anUnsignedInt & 0x0000FF00L) >> 8;
buf[3] = (anUnsignedInt & 0x000000FFL);
[/code]

但是,问题并没有解决。看来不是cast问题。猛然醒悟,原来是从String转成byte的时候出问题了!看来整个Class都要修改了,再次郁闷一下。

总结:Java去掉了无符号的整数,据说本意是为了简化编程,但是事实上在做网络程序时,我们需要应用大量的无符号整数。另外,Java的一些内部机制也会对编程造成困惑,例如从String生成byte数组的算法。但是这些特别的地方一般的教授或者教材并不作介绍。因此,Java特别适合做Top-level程序(最高等级,即应用程序级)。

最后的一点个人总结:我这个智商没办法凌驾于Java之上,最多也就只能用用C语言了……


注:有关Java中unsigned number的详见 http://darksleep.com/player/JavaAndUnsignedTypes.html

已有 2 条评论
  1. sephiroth sephiroth

    你好,蜗牛大侠,你是07年就遇到了啊,我最近也遇到了,试了下:
    byte[] start = new byte[]{-1, -1, -1, -1};
    for(byte b:start){
    System.out.print(b + ",");
    }
    System.out.println();
    String s = new String(start);
    byte[] end = s.getBytes();
    for(byte b:end){
    System.out.print(b + ",");
    }
    System.out.println();
    然后结果是:
    -1,-1,-1,-1,
    63,63,63,63,
    所以负数字节在做字节数组字符串转换时,java没处理好啊,或者是我理解错误?
    这个你还记得当初是怎么解决的吗,我也是要在socket通信里开发一个接口遇到这些问题了,好头疼...多谢.

  2. snailium snailium

    [quote=sephiroth]你好,蜗牛大侠,你是07年就遇到了啊,我最近也遇到了,试了下:
    byte[] start = new byte[]{-1, -1, -1, -1};
    for(byte b:start){
    System.out.print(b + ",");
    }
    System.out.println();
    String s = new String(start);
    byte[] end = s.getBytes();
    for(byte b:end){
    System.out.print(b + ",");
    }
    System.out.println();
    然后结果是:
    -1,-1,-1,-1,
    63,63,63,63,
    所以负数字节在做字节数组字符串转换时,java没处理好啊,或者是我理解错误?
    这个你还记得当初是怎么解决的吗,我也是要在socket通信里开发一个接口遇到这些问题了,好头疼...多谢.[/quote]
    问题出在把“-1”转换成字符串的步骤上
    Java不知道“-1”对应的是哪个字符,所以用“?”代替
    而“?”的ASCII编码就是63

添加新评论