(转) Java中的负数及基本类型的转型详解
(转) https://my.oschina.net/joymufeng/blog/139952
面这行代码的输出是什么?

下面两行代码的输出相同吗?

请尝试在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节中引用了一些转型规则,应用这些规则可以很容地解决常见的转型问题 七、参考引用 1. 阮一峰-关于2的补码
http://www.ruanyifeng.com/blog/2009/08/twos_complement.html 2. wikipedia-Sign extension
http://en.wikipedia.org/wiki/Sign_extension
(转) Java中的负数及基本类型的转型详解的更多相关文章
- java中包的命令行(cmd)操作详解
一.什么是包? 为了更好地组织类,防止在一个空间下出现类重名,Java提供了包机制.包是类的容器,用于分隔类名空间(类型于C++中的命名空间).如果没有指定包名,所有的示例都属于一个默认的无名包(又称 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- Java中String做为synchronized同步锁使用详解
Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...
- Java中使用Scanner类进行键盘的输入详解
我们在使用Java写代码时,经常会遇到从键盘输入字符串等操作,这时候我们需要用到的是我们的Scanner类来实现获取用户从键盘上的输入操作. Scanner类是一个基于正则表达式的文本扫描器,它可以从 ...
- java中四种访问修饰符区别及详解全过程
客户端程序员:即在其应用中使用数据类型的类消费者,他的目标是收集各种用来实现快速应用开发的类. 类创建者:即创建新数据类型的程序员,目标是构建类. 访问控制存在的原因:a.让客户端程序员无法触及他们不 ...
- (转)java中静态代码块的用法 static用法详解
一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来 ...
- java中静态代码块的用法 static用法详解(转)
(一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序 ...
- 关于Java中的程序,进程和线程的详解...
程序:一段静态的代码,一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体,是应用软件执行的蓝本. 进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个 ...
- 【转】java中静态代码块的用法 static用法详解
原文网址:http://www.cnblogs.com/panjun-Donet/archive/2010/08/10/1796209.html (一)java 静态代码块 静态方法区别一般情况下,如 ...
随机推荐
- 深入解析CNN pooling 池化层原理及其作用
原文地址:https://blog.csdn.net/CVSvsvsvsvs/article/details/90477062 池化层作用机理我们以最简单的最常用的max pooling最大池化层为例 ...
- 在CentOS7上搭建Kubernetes
来源 中文教程 http://blog.51cto.com/devingeng/2096495?from=singlemessage 官方文档 https://kubernetes.io/docs/s ...
- CentOS7 通过 YUM 升级 VIM8
Run 就完了: rpm -Uvh http://mirror.ghettoforge.org/distributions/gf/gf-release-latest.gf.el7.noarch.rpm ...
- 阶段3 2.Spring_04.Spring的常用注解_6 用于注入数据的注解
@Qualifier 指定id为accountDao1 测试 如果把Autowired注释掉的话, 就会报空指针异常.就是没有注入进来 @Qualifier不能独立使用必须和Autowired配合使用 ...
- opensuse终端命令行安装编码解码器
1) 添加必需的软件源:zypper addrepo -f http://packman.inode.at/suse/openSUSE_Leap_15.1/ packmanzypper addrepo ...
- Unity 声音与录音与麦克风实时播放
Unity AudioSource与MicroPhone以及AudioClip之间的关系. 下面是一个声音,长度为7秒钟,声音的实际数据本质是由采样点组成的的列表,一秒钟内的采样点数就是采样频率,下面 ...
- Scratch少儿编程系列:(十)系列总结及后续计划
一.系列文章的来由 本篇为该系列文章的一个简单总结, 从初次接触Scratch开始,在写本系列文章过程中,一边读书,一边通过例子做练习. 技术实现,对于我跟人来说,没有什么难度. 我相信,对于一个初次 ...
- 【VS开发】【图像处理】RGB各种格式
RGB格式 RGB组合格式 名字 RGB组合格式 描述 此格式用来匹配PC图形帧缓存.每个像素占据8,16,24或32个位,他们都是组合像素格式,其意为在内存中所有像素数据都是相邻排列的.当使用这些格 ...
- 【VS开发】【智能语音处理】语音信号处理之(一)动态时间规整(DTW)
语音信号处理之(一)动态时间规整(DTW) zouxy09@qq.com http://blog.csdn.net/zouxy09 这学期有<语音信号处理>这门课,快考试了,所以也要了解了 ...
- 访问DataGridView的Rows报了OutOfIndexRangeException错误
DataGridView绑定了一个List<Entity>实体集合,在遍历DataGridView的每一行DataBoundItem时候,如果符合某个条件的话,则移除List<Ent ...