我知道>>>是无符号右移,由于Java中的byte是有符号的8位,因此-1将表示为1111 1111.因此,对于以下代码:

byte b = (byte) -1;
b >>>= 1;
System.out.println(b);

它不应该打印127(二进制的0111 1111)吗?但我得到的结果总是-1,无论我执行>>>b次(例如,在一个循环中).

有谁能解释一下为什么以及用什么方法我可以得到我期望的结果(即执行无符号右移,其中-1右移一次等于127,在Java中为byte)?我的理解错了吗?多谢了!

推荐答案

你会遇到一系列非常奇怪的Java设计 Select ,这使得这段代码"撒谎"(做一件事是appears,但实际上它不会做那件事).让我们来分析一下:

Lesser known java aspect 1: byte, short, char, and boolean are inferior

在Java中,byteshortcharbooleaninferior个原语,intlongdoublefloatsuperior个原语.除了数组存储和数组加载之外,没有其他操作码.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);,其中bytea本身类型:

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位块中工作).

Java相关问答推荐

是否有一种格式模式,可以在除0之外的数字前面有正负符号?

找到允许的最大底片

我想了解Java中的模块化.编译我的应用程序时,我有一个ResolutionException

Java模式匹配记录

Junit with Mockito for java

需要一个找不到的jakarta.sistence.EntityManager类型的Bean

Java FX中的河内之塔游戏-在游戏完全解决之前什么都不会显示

确定Java中Math.Ranb()输出的上限

在JavaFX项目中注册组合框的控件FX验证器时,模块系统出错

按属性值从流中筛选出重复项

搜索列表返回多个频道

将PNG转换为位图自定义十六进制字符串

Kotlin Val是否提供了与Java最终版相同的可见性保证?

解析方法";javax/imageio/metadata/IIOMetadata.getAsTree(Ljava/lang/String;)Lorg/w3c/dom/Node时加载约束冲突

如果List是一个抽象接口,那么Collectors.toList()如何处理流呢?

如何在Record Java中使用isRecord()和RecordComponent[]?

JPA无手术同品种器械可能吗?

如何在Java中的重写方法参数中强制(Enum)接口实现?

使用DynamoDB增强客户端时未更新属性

声纳覆盖范围为 0%,未生成 jacoco.xml