你会遇到一系列非常奇怪的Java设计 Select ,这使得这段代码"撒谎"(做一件事是appears,但实际上它不会做那件事).让我们来分析一下:
Lesser known java aspect 1: byte
, short
, char
, and boolean
are inferior
在Java中,byte
、short
、char
、boolean
是inferior个原语,int
、long
、double
和float
是superior个原语.除了数组存储和数组加载之外,没有其他操作码.There is no opcode in java that adds 2 bytes together. It just does not exist..这是不可能的,因为javac
不知道要生成什么.所以,相反:
byte b = 5;
byte c = 10;
byte d = b + c;
实际上是指:
byte b = 5;
byte c = 10;
byte d = (int) b + (int) c;
因此,这是一个编译器错误--int + int
的结果是int
,如果不显式强制转换,则不允许try 将int
赋给byte
.
你可以随便看list of java bytecodes个.你会发现FADD,DADD,IADD和LADD(分别是'float add','double add','int add'和'long add').但是你不会找到byte/short/char的变体;没有BADD、CADD或SADD.
鲜为人知的java方面2:复合赋值运算符自动转换.
这句话:a += b;
实际上根本不等于a = a + b;
!我知道你是这样被教导的,但这是不正确的.实际上,它等于a = (byte) (a + b);
,其中byte
是a
本身类型:
double d = 5.5;
int x = 5;
x = x + d; // obviously, compiler error. Explicit cast needed.
对比:
double d = 5.5;
int x = 5;
x += d;
完全合法.结果x等于10.完整流程为:
- X是5.它被转换为
double
,因为Java只能在两个相同类型的事物之间进行数学运算.
d
等于5.5,已经是两倍了,很好.
- 执行
DADD
字节码;结果是10.5.
- 它被强制转换为
int
,结果是10
,该值被指定给x
.
如果你想看这个,就跑javap
.
将两者结合起来
因此,让我们分解您的代码:
byte b = (byte) -1;
这使得int-1(32‘1’位),然后将其转换为字节,结果是b
具有值1111 1111
.到目前为止,一切顺利,没有什么令人惊讶的事情.
b >>>= 1;
哈哈,男孩.这看起来很简单,但却非常复杂.它的语法是糖,意思是:
b = (byte) (((int) b) >>> 1);
要分解that,请执行以下操作:
(int) b
个结果为32个1位.b
在字节中是-1,将其转换为int会产生-1 int,即32个1位.
- 然后,
>>> 1
使其为零,后跟311位.
- 然后将其转换回一个字节,该字节..IS-1-8 1比特.
那么我该怎么做呢?
基本上,不要使用byte
.除非出现以下情况,否则永远不要使用劣质原语:
- 本质上,您可以在签名(即方法的返回类型或参数类型)中将它们用作API文档.
- 你可以做一个array.
byte[]
is非常有用,而且每个项目确实只需要1个字节.
对于所有其他方面(例如单个字段和针对数学的局部变量,例如您正在做的事情),don't.正如你在这里发现的那样,他们的行为并不像你认为的那样.
只需使用整数即可.如果您想要一个"无符号字节",只需创建一个int
变量并使用它:
byte b = (byte) -1;
int x = b & 0xFF; // x is now 0000...0000 1111 1111.
System.out.println(x); // prints 255
x >>= 1;
System.out.println(x); // prints 127
在64位体系 struct 上,byte
作为单个值(不是byte[]
-仅仅是byte
)比int
甚至可能是long
.Java没有分配更少的内存(因为所有东西都必须在字边界上对齐),操作速度也不快(CPU已经在64位块中工作).