详解 & 0xff 的作用
占用字节数 & 取值范围
Java一共有8种基本数据类型(原始数据类型):
类型 存储要求 范围(包含) 默认值 包装类 int 4字节(32位) -2^31~ 2^31-1 0 Integer short 2字节(16位) -215~215-1 0 Short long 8字节(64位) -2^63~2^63-1 0 Long byte 1字节(8位) -2^7~2^7-1 0 Byte float 4字节(32位) -3.4e+38 ~ 3.4e+38 0.0f Float double 8字节(64位) -1.7e+308 ~ 1.7e+308 0 Double char 2字节(16位) u0000~uFFFF(‘’~‘?’) ‘0’ Character boolean 1/8字节(1位) true, false FALSE Boolean
对于float与double类型:
内存结构:
float类型: 内存中共占4个字节,32bit位,其中bit位从高到低,依次是1位符号位、8位指数位、23位尾数位;
double类型:内存中共占8字节,64bit位,其中bit位从高到低,依次是1位符号位、11位指数位、52位尾数位;
大端模式与小端模式
大端模式是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中.
小端模式是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
大小端模式的由来
在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器)。
另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
大小端在内存中的存放方式举例
例如:
a) 16bit宽的数0x1234
1.Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
1 内存地址 2 0x4000 3 0x4001 4 存放内容 5 0x34 6 0x12
2.Big-endian模式CPU内存中的存放方式则为:
1 内存地址 2 0x4000 3 0x4001 4 存放内容 5 0x12 6 0x34
jvm使用的是大端
原码、反码、补码知识
源码
源码就是数字对应的二进制表示。
负数的源码 = 正数的源码取反再加1
反码
正数的反码就是源码自身。
负数的反码就是:保持源码符号位不变,其余各个位取反。
补码
正数的补码就是源码自身。
负数的补码就是: 反码基础上加1
如何根据补码计算源码:
- 最高位如果是0,即为正数,其补码即为源码;
- 最高位如果是1,即为负数,对此补码再次计算补码,结果即为源码(即:补码的补码即为源码)。
首先我们要都知道, &表示按位与,只有两个位同时为1,才能得到1, 0x代表16进制数,0xff表示的数二进制1111 1111 占一个字节.和其进行&操作的数,最低8位,不会发生变化.
1. 只是为了取得低八位
通常配合移位操作符>>使用
例如:java socket通信中基于长度的成帧方法中,如果发送的信息长度小于65535字节,长度信息的字节定义为两个字节长度。这时候将两个字节长的长度信息,
以Big-Endian的方式写到内存中
1 out.write((message.length>>8)&0xff);//取高八位写入地址 2 out.write(message.length&0xff);//取低八位写入高地址中
例如,有个数字 0x1234,如果只想将低8位写入到内存中 0x1234&0xff
0x1234 表示为二进制 0001001000110100
0xff 表示为二进制 11111111
两个数做与操作,显然将0xff补充到16位,就是高位补0
此时0xff 为 0000000011111111
与操作 1&0 =0 1&1 =1 这样 0x1234只能保留低八位的数 0000000000110100 也就是 0x34
2. 保证补码的一致性
我们只关心二进制的机器数而不关注十进制的值,那么byte &0xff只是对其最低8位的复制,通常配合逻辑或 ‘’|’'使用,达到字节的拼接,但不保证其十进制真值不变
1 public static void main(String[] args) { 2 byte b = -127;//10000001 3 int a = b; 4 System.out.println(a); 5 a = b&0xff; 6 System.out.println(a); 7 }//输出结果-127,129
乍一看,b是8位的二进制数,在与上0xff(也就是 11111111),不就是其本身吗,输出在控制台结果为什么是129呢?
首先计算机内的存储都是按照补码存储的,-127补码表示为 1000 0001
int a = b;将byte 类型提升为int时候,b的补码提升为 32位,补码的高位补1,也就是
1111 1111 1111 1111 1111 1111 1000 0001
负数的补码转为原码,符号位不变,其他位取反,在加1,正数的补码,反码都是本身
结果是 1000 0000 0000 0000 0000 0000 0111 1111表示为十进制 也是 -127
也就是 当 byte -> int 能保证十进制数不变,但是有些时候比如文件流转为byte数组时候,
我们不是关心的是十进制数有没有变,而是补码有没有变,这时候需要&上0xff
本例子中,将byte转为int 高24位必将补1,此时补码显然发生变化,在与上0xff,将高24重新置0,
这样能保证补码的一致性,当然由于符号位发生变化,表示的十进制数就会变了
1 1111 1111 1111 1111 1111 1111 1000 0001 2 3 & 4 5 0000 0000 0000 0000 0000 0000 1111 1111 6 7 结果是 8 9 0000 0000 0000 0000 0000 0000 1000 0001
和原来的补码 一致,但是显然符号位变化了,表示的十进制数发生变化,变为129
结论:
java中基本类型从小扩展到大的数据类型时候,正数因为符号位是0,无论如何都是补零扩展,但是负数补零扩展和补符号位扩展完全不同,
负数补符号位扩展,保证十进制数不变
例如 byte>>>int -127自动按照补符号位扩展,在高24位补符号位1,表示的十进制数不变
补零扩展,保证补码的一致性,但是表示的十进制发生变化
例如,本例中byte提升为int,&0xff的操作