一 参考博文

二 java中的无符号数和有符号数

在计算机中,可以区分正负的类型,称为有符号类型,无正负的类型,称为无符号类型。

使用二进制中的最高位表示正负

计算机中用补码表示数值;另外,用二进制的最高位表示符号,0表示正数、1表示负数。

无符号和有符号数的范围的区别

无符号数中,所有的位都用于直接表示该值的大小;有符号数中最高位用于表示正负,所以,正值时,该数的最大值就会变小:

无符号数:1111 1111 值:255

有符号数:0111 1111 值:127

同样一个字节,无符号的最大值是255,有符号的最大值是127

三 java中的基本类型

Java的原始类型里除了char是无符号类型之外,其他都是有符号数据类型,如果需要某个宽度的无符号类型,可以用>>>进行转化,这个是java的无符号右移操作符,或者使用下一个宽度的带符号类型来模拟,

例如,需无符号的short,就用int来模拟:

int toUnsigned(short s) {

return s & 0x0FFFF;

}

java中十进制的字面常理只有一个特性,就是所有的十进制字面常量都是正数,如果想写一个负的十进制,则需要在正的十进制字面常量前面加上“-”就好了。

但是十六进制或者八进制的字面常量就不一定是正数或者负数,如果最高位是1,那么就是负数:

System.out.println(0x80);//128

//0x81看作是int型,最高位(第32位)为0,所以是正数

System.out.println(0x81);//129

System.out.println(0x8001);//32769

System.out.println(0x70000001);//1879048193

//字面量0x80000001为int型,最高位(第32位)为1,所以是负数

System.out.println(0x80000001);//-2147483647

//字面量0x80000001L强制转为long型,最高位(第64位)为0,所以是正数

System.out.println(0x80000001L);//2147483649

四 补码与真值

这里先看一个问题:

@Test

public void test01(){

System.out.println(0x80000000); // -2147483648

}

这个结果是怎么得来的?

要搞明白这个问题,得先明白几个概念:

机器数:

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

比如,十进制中的数 3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。那么,这里的 00000011 和 10000011 就是机器数

真值:

因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。

所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值(即补码表示的值)。

例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

计算真值

就拿-3来说,机器数为 10000011,那么补码是 11111101,所以真值就是补码的值:

补码求值公式:补码的最高位有效位乘以(-1),然后按一般求二进制的方法求值

例如:

-3的补码 11111101 = (-1)12^7 + 12^6+.... 12^0 = -3

3的补码 00000011 = (-1)027+........1*20= 3

0x80000000问题解析

再来看0x80000000为什么等于-2147483648,Java中用此十六进制表示int的最小值:

/**

* A constant holding the minimum value an {@code int} can

* have, -231.

*/

@Native public static final int MIN_VALUE = 0x80000000;

此十六进制数内存中存储的的确是0x80000001的二进制码。因为使用十六进制给int赋值时,这里的十六进制是补码形式。

也就是说,我们给变量赋的是补码,不是源码,所以会直接把0x80000001这个补码存入内存

补码求值得: 0x80000000 = (-1)1231+.....+0*20 = -2147483648

所以这个值是这样来的!

五 java中的数据类型符号扩展

先看一个jdk源码中int转为long用到的方法:

@Test

public void test03(){

final long l = -5 & 0xffffffffL;

System.out.println(l); // 4294967291

}

如果运算一个操作数是long型,而另一个操作数是int类型。为了执行该计算,Java将int类型的数值用拓宽原生类型转换提升为long类型,然后对两个long类型数值相加。

因为int是有符号的整数类型,所以这个转换执行的是符号扩展。

-5 转换为long再转换为二进制,0xffffffff转换为二进制

进行与运算:

1111111111111111111111111111111111111111111111111111111110000101

0000000000000000000000000000000011111111111111111111111111111111

---------------------------------------------------------------------- & 与运算,两个都为1才为1,否则为0

0000000000000000000000000000000011111111111111111111111110000101= 4294967173 (十进制)

为什么-5转long前面要补1呢,这里就需要知道符号扩展规则:

窄的整型转换成较宽(字节数多)的整型时符号扩展规则:

如果最初的数值类型是有符号的,那么就执行符号扩展(即如果符号位为1,则扩展为1,如果为零,则扩展为0);

如果它是char,那么不管它将要被提升成什么类型,都执行零扩展,

如果将一个char数值c转型为一个宽度更宽的整型,并且希望有符号扩展,那么就先将char转型为一个short,它与char上个具有同样的宽度,但是它是有符号的

宽的整型转换成窄的整型直接截取低位的值,高位扔掉

所以上面-5符号是1,所以进行符号扩展前面都补1,补成long(64位),再进行位运算得出结果!

六 Java中byte转换int时与0xff进行与运算的原因

jdk源码中byte转int用到了 & 0xff,比如String的API:

public static char charAt(byte[] value, int index) {

if (index < 0 || index >= value.length) {

throw new StringIndexOutOfBoundsException(index);

}

return (char)(value[index] & 0xff);// 先转int,再转char

}

这里为什么要用与运算呢? 因为char是无符号类型,所以不能进行符号扩展,需要零扩展,即前面补0

窄整型->宽整型要进行符号扩展,这里byte->cahr是窄到宽,如果不想进行符号扩展,则需要&0xff处理,先转int消除掉符号扩展,再转char即可

(b & 0xff)的结果是32位的int类型,前24被强制置0,后8位保持不变,然后转换成char型时,直接截取后16位。这样不管b是正数还是负数,转换成char时,都相当于是在左边补上8个0,即进行零扩展而不是符号扩展

至于为什么要进行零扩展: 因为char是无符号类型,他会把 1111 1111 当做65535而不是-1,,所以你前面补1的话数就会变很大,所以这里需要进行0扩展,于是 & 0xff这种骚操作就来了,这里确实有点绕!如果不看源码(并且要认真看啊,哈哈)一般发现不了这种问题

再比如下面代码:

@Test

public void test01(){

byte b=-1;

System.out.println((int)b); // -1

System.out.println(b & 0xff); // 255

}

这里第二行255应该都好说,高位清零就是,至于直接强转为-1,那么符号扩展之后补码为11111111111111111111111111111111,求出结果原码:100000000000000000000000000001 还是-1,所以就是上面的结果,原理就是这样!

主要就是一个符号扩展延伸出来的问题!

java 无符号 类型_java中符号类型和无符号类型的问题分析相关推荐

  1. java的原生数据类型_Java中的8种原生数据类型(Primitive Data Types)分析

    八种数据类型 类型 int short long byte float double char boolean 字节数 4 2 8 1 4 8 4 JVM相关 大小 -2147483648~21474 ...

  2. java 字符串原样输出_Java 中如何原样输出转义符号

    标签: Java 中的转义字符有好几种,常见的有: 八进制转义字符,格式:\ + 1到3位八进制数字,如\1, \20,范围为 \0 ~ \377,即最大值为255. Unicode转义字符,格式:\ ...

  3. java double转换符_java中字符串怎么转换成double类型

    展开全部 public class Demo { public static void main(String[] args) { Demo demo = new Demo(); String str ...

  4. Java int -1无符号右移_java中的无符号右移

    java中的byte类型在运算过程中都会被转换为int类型进行运算,这样在对负的byte类型进行无符号右移的时候会出现和有符号右移同样的结果. example:11110000>>> ...

  5. java 7种枚举类型_Java中的枚举类型

    枚举类比较用 == 还是 equals,有啥区别? java 枚举值比较用 == 和 equals 方法没啥区别,两个随便用都是一样的效果.因为枚举 Enum 类的 equals 方法默认实现就是通过 ...

  6. java中三种转string的方法_java中int,char,string三种类型的相互转换

    如何将字串 String 转换成整数 int? int i = Integer.valueOf(my_str).intValue(); int i=Integer.parseInt(str); 如何将 ...

  7. java判断类型_Java中类型判断的几种方式 - 码农小胖哥 - 博客园

    1. 前言 在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式. 2. instanceof instanceof是Java的一个运算符,用来判断一个 ...

  8. java不可变类型_Java中的值类型:为什么它们不可变?

    java不可变类型 值类型不必是不变的. 但是他们是. 在上一篇文章中,我讨论了Java中指针与引用之间的区别以及如何传递方法参数(按值传递或按引用传递). 这些与Java中尚不存在的值类型密切相关( ...

  9. java协变返回类型_Java中的协变返回类型

    java协变返回类型 协变返回类型 (Covariant return type) The covariant return type is that return type which may va ...

最新文章

  1. oracle技术之使用rman找回被误删除表空间
  2. fireworks做图的最高长度
  3. android多行文本框hint居中,在安卓等移动浏览器中placeholder中的文字不垂直居中问题...
  4. mysql数据库事件不执行_如何查看mysql事件是否执行
  5. 关于使用安装Adobe绿色精简版所需运行库
  6. Django项目与中间件与celery
  7. php5.4 curl,PHP5.0~5.6 各版本兼容性cURL文件上传功能实例分析
  8. Spring Cloud Eureka(三)实现一个高可用的注册中心
  9. mysql中timestamp的自动生成与更新
  10. PMP考试教材有哪些?
  11. 简洁好用的Geek Unіnstaller
  12. 国内测试看Netflix
  13. C#爬取数据_详细篇
  14. 【android开发】手机应用管理器的实现之获取应用列表(一)
  15. 深富策略:个股情绪偏弱 市场继续缩量震荡
  16. 把QQ群共享当做网盘用感觉还不错
  17. 英伟达创始人出生 | 历史上的今天
  18. MapServer 7.0.3 Documentation 翻译
  19. “整合”还是“混合”——多因子组合的构建
  20. 知道密码,如何去除Word文档的各种保护?

热门文章

  1. 1123 Is It a Complete AVL Tree (30 分)【难度: 难 / 平衡树 未完成】
  2. Rational rose的安装
  3. c# xml html标签,XML文件到html表(循环)C#
  4. java中怎样创建多个对象,java中StringBuilder.appent方法创建几个对象
  5. python里res有什么用_python – 为什么在tensorflow中构建resnet模型时使用固定填充...
  6. lua 调用文件中的函数调用_四、C++获得Lua的变量和Table的值
  7. 为防止员工带薪拉屎,快手公司推出“计时厕所”?官方称只是为了测试!
  8. 7个IntelliJ IDEA必备插件,提高编码效率
  9. JSON与XML的区别比较(非常全面)
  10. Java常用类之要点总结