您遇到了一系列非常奇怪的java设计选择,这些选择使代码成为“谎言”(它
出现
做一件事,但实际上不会做那件事)。让我们来分解一下:
鲜为人知的java方面1:
byte
,
short
,
char
和
boolean
是低劣的
在java中,
字节
,
短的
,
烧焦
,
布尔值
是吗
较差的
基本体,具有
int
,
long
,
double
和
float
是
优越的
基元。除了数组存储和数组加载之外,没有用于下级的操作码。
java中没有将2个字节加在一起的操作码。它根本不存在。
.考虑到这一点,真的不可能做到
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
,并尝试分配
int
到
字节
在没有显式强制转换的情况下是不允许的。
你可以随便看看
list of java bytecodes
。你会发现FADD、DADD、IADD和LADD。但你不会发现BADD、CADD或SADD。
鲜为人知的java方面2:复合赋值运算符自动转换。
这个:
a += b;
实际上与
a = a + b;
完全我知道这是你被教导的,但这是不正确的。事实上,它等于
a = (byte) (a + b);
在哪里
字节
是类型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。此转换为
双重的
因为java只能在两个相同类型的事物之间进行数学运算。
-
d
是5.5,已经是双人间了,很好。
-
DADD
执行字节码;其结果是10.5。
-
这是铸造到
int
,导致
10
,分配给
x
.
跑
javap
如果你想看这个。
将两者结合
因此,让我们分解一下您的代码:
byte b = (byte) -1;
这使得int-1(32个“1”位),然后将其强制转换为byte,从而得到
b
具有价值
1111 1111
。到目前为止,一切都很好,这里没什么奇怪的。
b >>>= 1;
胡小子。这看起来很简单,但很复杂。它的语法糖用于:
b = (byte) (((int) b) >>> 1);
打断
那个
向下:
-
(int) b
产生32个1比特。
b
在字节中为-1,将其强制转换为int将产生-1的int,即32个1位。
-
>>> 1
然后将其设为0,后面跟着31个1比特。
-
然后将其转换回一个字节,该字节。。是-1-8个1位。
那么我该怎么做呢?
不使用
字节
大体上除非在以下情况下,否则永远不要使用劣质基元:
-
本质上,在签名(即方法的返回类型或参数类型)中将它们用作API文档。
-
你做一个数组。
byte[]
是
非常有用,而且每个项目实际上只需要1个字节。
对于所有其他事情(例如单个字段和针对数学的局部变量,例如您正在做的事情),
不要
。正如你在这里发现的那样,他们的行为并不像你想象的那样。
只需使用int。如果你想要一个“无符号字节”,只需制作一个
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
字节
作为单个值(不是
字节[]
-只是
字节
)
在任何方面都没有更高效
比
int
甚至可能
长的
,基于64位体系结构。Java不会分配更少的内存(因为所有东西都必须在字边界上对齐),操作也不会更快(CPU已经在64位块中工作了)。