Java Sign扩展

Java多播问题

在Java中,如果我们执行以下操作,则将启动Sign扩展

  • 扩展原始转换–从一种类型转换为另一种类型,这涉及到增加原始类型的位,例如,将byte (8 bits)int (32 bits)
  • 按位右移n位>> n

符号扩展名是在保留数字的符号(正号和负号)的同时增加位数的操作。 除一个条件外,Sign扩展名用最高有效位(msb)或最左边的位的原始位填充增加的位-将无符号的char为其他类型,请向下滚动至3. Java Multicast进行解释。

本文还通过以下代码解释了著名的Java多播问题。 你能回答吗?

byte b = -1;                    // twos complement
  char c = (char) (b);            // byte -> int -> char (widening and narrowing type) (sign extension)
  System.out.println((int)c);     // char -> int (zero extension), output = 65535

  c = (char) (b & 0xff);          // byte -> int (sign extension)
  System.out.println((int) c);    // char -> int (zero extension), output = 255

1. Java Sign扩展–扩展原始转换

例如,我们将一个byte (8位)转换为int (32位)。

正数
1.1这是二进制格式的byte 10 10,8位(1个字节)。

0000 1010 = 10

如果我们将byte (8位)强制转换/加宽为int (32位,4字节),则额外位的值(1或0)是什么?

# byte, 1 byte, 8 bits
0000 1010 = 10

# int, 4 bytes, 32 bits
???? ???? | ???? ???? | ???? ???? | 0000 1010 = 10

答案是符号扩展。 它取决于“原始”最高有效位(msb)或最左侧的位。 在上面的示例中, byte 100000 1010的msb为0 ,并且符号扩展用零填充所有额外的未知位。

{0}000 1010 , {0} = most significant bit or leftmost bit.

byte 10 intint ,结果仍然为10

0000 0000 | 0000 0000 | 0000 0000 | 0000 1010 = 10
byte aByte = 10;
  int aByte1 = (int) aByte;
  System.out.println(aByte1);  // output = 10

负数
1.2对于byte -10 ,Java使用二进制补码表示负值。

# two's complement formula

0000 1010 = 10
1111 0101 (invert bits)
1111 0110 (add 1)
1111 0110 = -10

如果我们将byte -10 (8位)强制转换/扩展为int (32位,4字节),则额外位的值(1或0)是多少?

???? ???? | ???? ???? | ???? ???? | 1111 0110 = -10

对于byte -101111 0110 ,最显著位1111 01101 ,而符号扩展填充所有的未知位一个。

{1}111 0110 , {1} = most significant bit or leftmost bit.

byte -10int ,结果仍然为-10

1111 1111 | 1111 1111 | 1111 1111 | 1111 0110

对于二进制补码(最左边的1为负,0为正)

# two's complement formula

1111 1111 | 1111 1111 | 1111 1111 | 1111 0110 (this is a negative number)
1111 1111 | 1111 1111 | 1111 1111 | 1111 0101 (sub 1)
0000 0000 | 0000 0000 | 0000 0000 | 0000 1010 (invert bits)
0000 0000 | 0000 0000 | 0000 0000 | 0000 1010 = 10
1111 1111 | 1111 1111 | 1111 1111 | 1111 0110 = -10
byte aByte = -10;
  int aByte1 = (int) aByte;
  System.out.println(aByte1); // output = -10

困难的部分是了解两者的互补

2. Java符号扩展–按位右移>>

按位移位运算符>> (也称为算术右移),它在移位后保留符号(正数或负数)。

例如,这里是整数10。在Java中, int是32位4字节。

0000 0000 | 0000 0000 | 0000 0000 | 0000 1010

然后我们右移3位10 >> 3 。 对于整数10{0=msb}0001010 ,最高有效位为零,并且符号扩展用零填充所有未知位。

???0 0000 | 0000 0000 | 0000 0000 | 0000 0001 | 010 >> 3

10 >> 3的答案是1

0000 0000 | 0000 0000 | 0000 0000 | 0000 0001 = 1
System.out.println(10>>3); // output = 1

进一步阅读
Java >>和>>>按位移位运算符

3. Java组播-符号扩展和零扩展。

到目前为止,一切看起来都很简单明了。 真正的挑战是多播,这使一切变得复杂。

查看下面的Java多播示例(如果我不记得记错的话,我从一个论坛上找到了此代码片段,其原文来自Java Puzzle丛书)。

byte b = -1;                    // twos complement
  char c = (char) (b);            // byte -> int -> char (widening and narrowing type) (sign extension)
  System.out.println((int)c);     // char -> int (zero extension), output = 65535

  c = (char) (b & 0xff);          // byte -> int (sign extension)
  System.out.println((int) c);    // char -> int (zero extension), output = 255

上面的示例涉及多播,从byte -> int > char > int ,二进制补码,加宽原始转换,缩小原始转换,符号扩展,零扩展以及按位屏蔽。 让我们一一分解。

3.1 Java使用二进制补码表示否定。

0000 0001 = 1
  1111 1110 = (invert bits)
  1111 1111 = (add 1)
  1111 1111 = -1 in twos complement

  byte b = 1111 1111

3.1在Java byte是一个有符号字节,为8位; 而char是一个无符号的2字节16位。 Java的无法铸造的bytechar直接(不能有符号类型转换为无符号类型),因此它投/拓宽byteint第一和缩小到char

byte b = -1;  
  char c = (char) (b);                           = byte -> int -> char

  1111 1111                                      = byte (8 bits)
  1111 1111 | 1111 1111 | 1111 1111 | 1111 1111  = int  (32 bits, sign extension)
  1111 1111 | 1111 1111                          = char (16 bits)

  char c = 1111 1111 | 1111 1111

3.2这个(int)c很有趣; 它将一个char 2字节转换为一个int 4字节。 首先,我们可能认为Sign扩展将执行并用原始的最高有效位(即1)填充增加的位。

char c = 1111 1111 | 1111 1111
  int(c) = ???? ???? | ???? ???? | 1111 1111 | 1111 1111
  int(c) = 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 (sign extension) ??? but why the output is 65535?

答案是否定的,在上述情况下,Java使用零扩展将零位填充为增加的位。

字符->任何类型=零扩展
请记住, char是无符号类型,如果我们将无符号类型char为其他任何类型,则使用zero extension ,而不是“符号扩展名”。

什么是零扩展?
零扩展将所有增加的位填充为零。 此零扩展名也适用于逻辑右移运算符>>>

以下是int(c)的正确答案。

char c = 1111 1111 | 1111 1111
int(c) = ???? ???? | ???? ???? | 1111 1111 | 1111 1111
int(c) = 0000 0000 | 0000 0000 | 1111 1111 | 1111 1111 (zero extension on unsigned char), the output is 65535.

3.4现在,我们来看以下语句。

c = (char) (b & 0xff);          // mask, int -> char
  System.out.println((int) c);    // char -> int, output: 255, but why?

重写为

int i = (b & 0xff)
  c = (char)i
  System.out.println((int) c);

b & 0xff将返回一个int 。 Java的铸byteint ,并执行bitwise &与此0xff ,又名掩盖。

byte b      = 1111 1111

  int         = 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111  (sign extension)
                &
  0xff        = 0000 0000 | 0000 0000 | 0000 0000 | 1111 1111

  int i       = 0000 0000 | 0000 0000 | 0000 0000 | 1111 1111

  c = (char)i = 0000 0000 | 1111 1111                          (narrow down, int -> char)

最后一个(int) c ,将一个无符号charint ,零扩展名。

c           = 0000 0000 | 1111 1111

  (int)c      = ???? ???? | ???? ???? | 0000 0000 | 1111 1111  (zero extension)

  (int)c      = 0000 0000 | 0000 0000 | 0000 0000 | 1111 1111

在二进制补码中,第一个最左边定义的符号,1是负数,0是正数。

0000 0000 | 0000 0000 | 0000 0000 | 1111 1111
  = 1x2^0 +... 1x2^8
    1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255

做完了 感谢您阅读这篇长文章。

注意
如果您发现任何错别字,错误或错误解释,请告诉我。

参考文献

翻译自: https://mkyong.com/java/java-sign-extension/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值