2进制怎样表示负数,byte&oxff到底为什么 (byte) 0x97=-105:java 2进制补码
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了2进制怎样表示负数,byte&oxff到底为什么 (byte) 0x97=-105:java 2进制补码,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9708字,纯文字阅读大概需要14分钟。
内容图文
![2进制怎样表示负数,byte&oxff到底为什么 (byte) 0x97=-105:java 2进制补码](/upload/InfoBanner/zyjiaocheng/798/67f7a4b7307a40eb9c0368f409499310.jpg)
在二进制码中,为了区分正负数,采用最高位是符号位的方法来区分,正数的符号位为0、负数的符号位为1。剩下的就是这个数的绝对值部分,可以采用原码、反码、补码3种形式来表示绝对值部分。
原码最简单,也最好理解。原码就是绝对值的二进制数形式:例如+7的8位二进制原码是00000111,-7的8位二进制原码是10000111。
但对于二进制运算而言,原码的运算不够方便,当两个数相加时,先要判断这两个数的符号是否相同,符号不同的话,还要判断哪一个数的绝对值更大。所以在计算机中,通常都是采用补码形式。
正整数的补码与原码形式相同,例如+7的8位二进制补码是00000111;而负整数的补码则可以通过下列方式得到:将这个负整数的绝对值求反加1,连同符号位1一起表示就可以了。例如-7的8位二进制补码:将-7的绝对值7求反加1得1111001,连同符号位1一起就是11111001。
你也可以练习一下+13和-13的8位二进制补码:+13d=00001101,-13d=11110011。
(byte) 0x97=-105
实际上在数值类型转换时,只有当遇到负数时才会出现问题,根本原因就是Java中的负数不是采用直观的方式进行编码,而是采用“2的补码”方式,这样的好处是加法和减法操作可以同时使用加法电路完成,但是在开发时却会遇到很多奇怪的问题,例如(byte)128的结果是-128,即一个大的正数,截断后却变成了负数。3.2节中引用了一些转型规则,应用这些规则可以很容地解决常见的转型问题。
下面这行代码的输出是什么?
public static void main(String[] args) {
System.out.println(0xffffffff);
}
下面两行代码的输出相同吗?
public static void main(String[] args) {
byte b=-1;
System.out.println((int)(char)b);
System.out.println((int)(char)(b & 0xff));
}
请尝试在Eclipse中运行上面的两个代码片段,如果你对输出结果感到很惊讶,请继续往下读...
正如你所看到的:
第1个代码片段的运行结果是:-1
第2个代码片段的运行结果是:65535和255
上面的两个代码片段来源于《Java解惑》的第6个小问题“多重转型”,原题目内容如下:
public class Multicast{
public static void main (String[] args){
System.out.println((int)(char)(byte)-1);
}
}
上面的代码中连续进行了3次类型转换,最后的结果会回到-1吗?答案当然是不会,它输出的结果是65535。下面我为大家整理了相关的基础知识,相信大家读完后应该就知道其中的原因了。
一、Java中如何编码负数?
Java采用”2的补码“(Two's Complement)编码负数,它是一种数值的编码方法,要分二步完成:第一步,每一个二进制位都取相反值,0变成1,1变成0。比如,+8的二进制编码是00001000,取反后就是11110111。第二步,将上一步得到的值加1。11110111就变成11111000。所以,00001000的2的补码就是11111000。也就是说,-8在计算机(8位机)中就是用11111000表示。关于“2的补码”的详细信息,请参考阮一峰的博文《关于2的补码》,博文地址附在本文的参考部分。
二、什么是符号扩展(Sign Extension)?
符号扩展(Sign Extension)用于在数值类型转换时扩展二进制位的长度,以保证转换后的数值和原数值的符号(正或负)和大小相同,一般用于较窄的类型(如byte)向较宽的类型(如int)转换。扩展二进制位长度指的是,在原数值的二进制位左边补齐若干个符号位(0表示正,1表示负)。
举例来说,如果用6个bit表示十进制数10,二进制码为"00 1010",如果将它进行符号扩展为16bits长度,结果是"0000 0000 0000 1010",即在左边补上10个0(因为10是正数,符号为0),符号扩展前后数值的大小和符号都保持不变;如果用10bits表示十进制数-15,使用“2的补码”编码后,二进制码为"11 1111 0001",如果将它进行符号扩展为16bits,结果是"1111 1111 1111 0001",即在左边补上6个1(因为-15是负数,符号为1),符号扩展前后数值的大小和符号都保持不变。
三、Java类型转换规则
1. Java中整型字面量
Java中int型字面量的书写方式有以下几种:
- 十进制方式,直接书写十进制数字
- 八进制方式,格式以0打头,例如012表示十进制10
- 十六进制方式,格式为0x打头,例如0xff表示十进制255
需要注意的是,在Java中012和0xff返回的都是int型数据,即长度是32位。
2. Java的数值类型转换规则
这个规则是《Java解惑》总结的:如果最初的数值类型是有符号的,那么就执行符号扩展;如果是char类型,那么不管它要被转换成什么类型,都执行零扩展。还有另外一条规则也需要记住,如果目标类型的长度小于源类型的长度,则直接截取目标类型的长度。例如将int型转换成byte型,直接截取int型的右边8位。
四、解析“多重转型”问题
连续三次类型转换的表达式如下:
(int)(char)(byte)-1
1. int(32位) -> byte(8位)
-1是int型的字面量,根据“2的补码”编码规则,编码结果为0xffffffff,即32位全部置1.转换成byte类型时,直接截取最后8位,所以byte结果为0xff,对应的十进制值是-1.
2. byte(8位) -> char(16位)
由于byte是有符号类型,所以在转换成char型(16位)时需要进行符号扩展,即在0xff左边连续补上8个1(1是0xff的符号位),结果是0xffff。由于char是无符号类型,所以0xffff表示的十进制数是65535。
3. char(16位) -> int(32位)
由于char是无符号类型,转换成int型时进行零扩展,即在0xffff左边连续补上16个0,结果是0x0000ffff,对应的十进制数是65535。
五、几个转型的例子
在进行类型转换时,一定要了解表达式的含义,不能光靠感觉。最好的方法是将你的意图明确表达出来。
在将一个char型数值c转型为一个宽度更宽的类型时,并且不希望有符号扩展,可以如下编码:
int i = c & 0xffff;
上文曾提到过,0xffff是int型字面量,所以在进行&操作之前,编译器会自动将c转型成int型,即在c的二进制编码前添加16个0,然后再和0xffff进行&操作,所表达的意图是强制将前16置0,后16位保持不变。虽然这个操作不是必须的,但是明确表达了不进行符号扩展的意图。
如果需要符号扩展,则可以如下编码:
int i = (short)c; //Cast causes sign extension
首先将c转换成short类型,它和char是 等宽度的,并且是有符号类型,再将short类型转换成int类型时,会自动进行符号扩展,即如果short为负数,则在左边补上16个1,否则补上16个0.
如果在将一个byte数值b转型为一个char时,并且不希望有符号扩展,那么必须使用一个位掩码来限制它:
char c = (char)(b & 0xff);
(b & 0xff)的结果是32位的int类型,前24被强制置0,后8位保持不变,然后转换成char型时,直接截取后16位。这样不管b是正数还是负数,转换成char时,都相当于是在左边补上8个0,即进行零扩展而不是符号扩展。
如果需要符号扩展,则编码如下:
char c = (char)b; //Sign extension is performed
此时为了明确表达需要符号扩展的意图,注释是必须的。
六、小结
实际上在数值类型转换时,只有当遇到负数时才会出现问题,根本原因就是Java中的负数不是采用直观的方式进行编码,而是采用“2的补码”方式,这样的好处是加法和减法操作可以同时使用加法电路完成,但是在开发时却会遇到很多奇怪的问题,例如(byte)128的结果是-128,即一个大的正数,截断后却变成了负数。3.2节中引用了一些转型规则,应用这些规则可以很容地解决常见的转型问题。
一、Java中如何编码负数?
Java采用”2的补码“(Two's Complement)编码负数,它是一种数值的编码方法,要分二步完成:第一步,每一个二进制位都取相反值,0变成1,1变成0。比如,+8的二进制编码是00001000,取反后就是11110111。第二步,将上一步得到的值加1。11110111就变成11111000。所以,00001000的2的补码就是11111000。也就是说,-8在计算机(8位机)中就是用11111000表示。关于“2的补码”的详细信息,请参考阮一峰的博文《关于2的补码》,博文地址附在本文的参考部分。
二、什么是符号扩展(Sign Extension)?
符号扩展(Sign Extension)用于在数值类型转换时扩展二进制位的长度,以保证转换后的数值和原数值的符号(正或负)和大小相同,一般用于较窄的类型(如byte)向较宽的类型(如int)转换。扩展二进制位长度指的是,在原数值的二进制位左边补齐若干个符号位(0表示正,1表示负)。
举例来说,如果用6个bit表示十进制数10,二进制码为"00 1010",如果将它进行符号扩展为16bits长度,结果是"0000 0000 0000 1010",即在左边补上10个0(因为10是正数,符号为0),符号扩展前后数值的大小和符号都保持不变;如果用10bits表示十进制数-15,使用“2的补码”编码后,二进制码为"11 1111 0001",如果将它进行符号扩展为16bits,结果是"1111 1111 1111 0001",即在左边补上6个1(因为-15是负数,符号为1),符号扩展前后数值的大小和符号都保持不变。
三、Java类型转换规则
-
Java中整型字面量
Java中int型字面量的书写方式有以下几种:
-
十进制方式,直接书写十进制数字
-
八进制方式,格式以0打头,例如012表示十进制10
-
十六进制方式,格式为0x打头,例如0xff表示十进制255
需要注意的是,在Java中012和0xff返回的都是int型数据,即长度是32位。
-
-
Java的数值类型转换规则
这个规则是《Java解惑》总结的:如果最初的数值类型是有符号的,那么就执行符号扩展;如果是char类型,那么不管它要被转换成什么类型,都执行零扩展。还有另外一条规则也需要记住,如果目标类型的长度小于源类型的长度,则直接截取目标类型的长度。例如将int型转换成byte型,直接截取int型的右边8位。
四、解析“多重转型”问题
连续三次类型转换的表达式如下:
(int)(char)(byte)-1
-
int(32位) -> byte(8位)
-1是int型的字面量,根据“2的补码”编码规则,编码结果为0xffffffff,即32位全部置1.转换成byte类型时,直接截取最后8位,所以byte结果为0xff,对应的十进制值是-1.
-
byte(8位) -> char(16位)
由于byte是有符号类型,所以在转换成char型(16位)时需要进行符号扩展,即在0xff左边连续补上8个1(1是0xff的符号位),结果是0xffff。由于char是无符号类型,所以0xffff表示的十进制数是65535。
-
char(16位) -> int(32位)
由于char是无符号类型,转换成int型时进行零扩展,即在0xffff左边连续补上16个0,结果是0x0000ffff,对应的十进制数是65535。
五、几个转型的例子
在进行类型转换时,一定要了解表达式的含义,不能光靠感觉。最好的方法是将你的意图明确表达出来。
在将一个char型数值c转型为一个宽度更宽的类型时,并且不希望有符号扩展,可以如下编码:
int i = c & 0xffff;
上文曾提到过,0xffff是int型字面量,所以在进行&操作之前,编译器会自动将c转型成int型,即在c的二进制编码前添加16个0,然后再和0xffff进行&操作,所表达的意图是强制将前16置0,后16位保持不变。虽然这个操作不是必须的,但是明确表达了不进行符号扩展的意图。
如果需要符号扩展,则可以如下编码:
int i = (short)c; //Cast causes sign extension
首先将c转换成short类型,它和char是 等宽度的,并且是有符号类型,再将short类型转换成int类型时,会自动进行符号扩展,即如果short为负数,则在左边补上16个1,否则补上16个0.
如果在将一个byte数值b转型为一个char时,并且不希望有符号扩展,那么必须使用一个位掩码来限制它:
char c = (char)(b & 0xff);
(b & 0xff)的结果是32位的int类型,前24被强制置0,后8位保持不变,然后转换成char型时,直接截取后16位。这样不管b是正数还是负数,转换成char时,都相当于是在左边补上8个0,即进行零扩展而不是符号扩展。
如果需要符号扩展,则编码如下:
char c = (char)b; //Sign extension is performed
此时为了明确表达需要符号扩展的意图,注释是必须的。
六、小结
实际上在数值类型转换时,只有当遇到负数时才会出现问题,根本原因就是Java中的负数不是采用直观的方式进行编码,而是采用“2的补码”方式,这样的好处是加法和减法操作可以同时使用加法电路完成,但是在开发时却会遇到很多奇怪的问题,例如(byte)128的结果是-128,即一个大的正数,截断后却变成了负数。3.2节中引用了一些转型规则,应用这些规则可以很容地解决常见的转型问题。
内容总结
以上是互联网集市为您收集整理的2进制怎样表示负数,byte&oxff到底为什么 (byte) 0x97=-105:java 2进制补码全部内容,希望文章能够帮你解决2进制怎样表示负数,byte&oxff到底为什么 (byte) 0x97=-105:java 2进制补码所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。