C/C++/Java数据类型比较及Java位操作运算讲解
2018-03-10 09:46
323 查看
Java 位操作这是一项很基础很基础的知识内容,在所有 Android 和 Java 开发者的学习之路上,大家都接触过,但是实际运用的场景却很少见,很多人估计都忘记有这个知识点了。事实上,在 C/C++ 开发领域因为与硬件的联系更紧密,所以位操作运算应用的更普遍。Java 因为面向对象的特性很多时候不需要接触位操作,但是在某些特定场景下,巧妙运用位操作,能够起到非常高效的的表现。这篇博文不谈应用,只详细讲解与位操作有关的知识点。
软件开发者都知道 10 进制、16 进制、8 进制。
比如数字 10 的各位进制形式表现如下。
虽然有很多种进制,但是实际上计算机所认识的数据只有 0 和 1,因此所有的数值不管它是十进制、十六进制也好都会统统在底层被翻译成二进制数值。
bit (位) bit 电脑记忆体中最小的单位,在二进位电脑系统中,每一 bit 可以代表 0 或 1 的数位讯号。所以它能表示的数字范围就是 0 ~ 1。
byte (字节) 一个 byte 由 8 bit 组成,所以理论上一个 byte 能表示的数据范围是 0 ~ 255。
<
4000
li>word (字) 一个 word 由 2 byte 组成,所以理论上一个 word 能表示的数据范围是 0 ~ 65535。
大家可以看这张图加深下理解。
一般计算机设备上,CPU 主要有 32 位和 64 位(当然,单片机有 8 位和 16 位),32 位 CPU 能够寻址的范围是 4 GB。所以过去的电脑设备内存最高一般只能到达 4 GB。后来,随着芯片技术的发展,越来越多的机器采用了 64 位 CPU。这使得机器的最大内存可以为 16 GB。
那么好,我们再来谈谈 32 位操作系统与 64 位操作系统。实际上它们分别是针对 CPU 类型设计的软件系统。
32 bit 是 4 byte。通常一条 CPU 指令是 4 byte。在 32 位操作系统上,如果一条 CPU 指令是 4 byte,那么 CPU 执行一次能够读取 32 bit 内容,所以一个指令周期内就能够完成指令,如果一条 CPU 指令是 8 byte 的话,那么 32 位操作系统就需要通过 2 个指令周期才能完成指令的读取,而对应的 64 位操作系统因为一次能够读取 64 bit 内容,所以它在一个指令周期就能够读取指令。所以,理论上,64
位的操作系统是要比 32 位操作系统要快 1 倍。
但还有几个需要大家注意的地方是:
1. 64 位 CPU 机器可以安装 32 位操作系统,但效率自然跟 32 位操作系统一样。
2. 32 位 CPU 机器也可以安装 64 位操作系统。
3. 64 位 CPU 机器安装 64 位操作系统才最有效率,但跟软件优化也有关系。
不同的操作系统平台,给 C/C++ 基本数据类型变量分配的字节是不一样的。
32位编译器:
64位编译器:
上面讲的是 C/C++ 在不同平台上的字节长度差别,但是对于 Java 而言,由于 Java 是跨平台语言,所以 JVM 表现下的基础数据字节长度其实都是一致的。
我们可以看到 Java 与 C/C++ 的基本数据类型字节长度有些不一致,所以涉及到网络通信交互或者是 JNI 开发时,数据的转换有时需要考虑下基础的字节长度。
本篇文章的主要内容是 Java 中的位操作,所以基础数据长度也是以 Java 中定义的为准。
我们已经知道了一个 int 型数值是 4 个字节。每个字节有 8 位。但对于一个 int 或者其它整数类型如 (long)的数值而言还要注意的是,它的最高位是符号位。
最高位为0表示正数。
最高位为1表示负数
原码 将一个数字转换成二进制就是这个数值的原码。
反码
分两种情况:正数和负数
正数 正数的反码就是原码。
负数 负数的反码是在原码的基础上,符号位不变 其它位都取反。
补码
仍然分正数和负数两种情况
正数 正数的补码就是原码。
负数 负数的补码在反码的基础上加1。
计算机在进行数值运算的时候,是通过补码表示每个数值的。
比如
最后的结果是1 0000 0000 0000 0010 这样的二进制,由于 int 类型只有 4 byte,所以最高位产生了溢出,进位 1 被丢弃。结果就变成了 0010 也就是 2,5 - 3 = 2 没有毛病。
位运算符包含与运算符、或运算符、取反运算符、异或运算符、左移运算符和右移运算符。在下面的内容中,我将会一一讲解。
需要注意的是,下面测试用的数据都是 int 类型,int 类型是 4 个字节长度,但是为了方便说明示例中用的数值我都用 1 个字节表示。希望不会给大家造成困扰。
规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值都是 1,则结果值相应的 bit 就是 1,否则为 0.
3 & 5 = 1 这是因为
按照规则,将两个数值按照低位到高位一一对齐运算,因为只有第 0 位都为 1,所以计算结果为 1.
规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值只要 1 个为 1,则结果值相应的 bit 就是 1,否则为 0。
3 | 5 = 7 这是因为
规则 对操作数的每一位进行操作,1 变成 0,0 变成 1。
规则 两个操作数进行异或时,对于同一位上,如果数值相同则为 0,数值不同则为 1。
3 ^ 5 = 6,这是因为
值得注意的是 3 ^ 5 = 6,而 6 ^ 5 = 3
针对这个特性,我们可以将异或运算作为一个简单的数据加密的形式。比如,将一个mp4文件所有数值与一个种子数值进行异或得到加密后的数据,解密的时候再将数据与种子数值进行异或一次就可以了。
所以说异或运算可以作为简单的加解密运算算法。
规则 a >> b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向右方向移动 b 位,符号位不变,高位空出来的位补数值 0。
大家发现什么规律没有?a >> b = a / ( 2 ^ b ) ,所以 5 >> 1= 5 / 2 = 2,11 >> 2 = 11 / 4 = 2。
规则 a << b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向左方向移动 b 位,符号位不变,低位空出来的位补数值 0。
很明显就可以看出 a << b = a * (2 ^ b)
综合上面两个可以看到,如果某个数值(仅指正数,正数的原反补在计算机中一致;因为负数在计算机中以补码形式存在)右移 n 位,就相当于拿这个数值去除以 2 的 n 次幂。如果某个数值(正数/负数)左移 n 位,就相当于这个数值乘以 2 ^ n。
32位机和64位机的区别及基本数据类型占字节数
转载:https://juejin.im/entry/58f9b6118d6d8100588060d6
基础大讲堂
所有数值都是2进制
软件开发者都知道 10 进制、16 进制、8 进制。比如数字 10 的各位进制形式表现如下。
十进制:10 八进制:012 十六进制:0x0a 二进制:1010
虽然有很多种进制,但是实际上计算机所认识的数据只有 0 和 1,因此所有的数值不管它是十进制、十六进制也好都会统统在底层被翻译成二进制数值。
int a = 5; //0101 就是 a 的二进制表示。 int b = 520; //1000001000 就是 b 的二进制表示
bit、byte、world
bit (位) bit 电脑记忆体中最小的单位,在二进位电脑系统中,每一 bit 可以代表 0 或 1 的数位讯号。所以它能表示的数字范围就是 0 ~ 1。byte (字节) 一个 byte 由 8 bit 组成,所以理论上一个 byte 能表示的数据范围是 0 ~ 255。
<
4000
li>word (字) 一个 word 由 2 byte 组成,所以理论上一个 word 能表示的数据范围是 0 ~ 65535。
大家可以看这张图加深下理解。
32 位与 64 位操作系统。
一般计算机设备上,CPU 主要有 32 位和 64 位(当然,单片机有 8 位和 16 位),32 位 CPU 能够寻址的范围是 4 GB。所以过去的电脑设备内存最高一般只能到达 4 GB。后来,随着芯片技术的发展,越来越多的机器采用了 64 位 CPU。这使得机器的最大内存可以为 16 GB。那么好,我们再来谈谈 32 位操作系统与 64 位操作系统。实际上它们分别是针对 CPU 类型设计的软件系统。
32 bit 是 4 byte。通常一条 CPU 指令是 4 byte。在 32 位操作系统上,如果一条 CPU 指令是 4 byte,那么 CPU 执行一次能够读取 32 bit 内容,所以一个指令周期内就能够完成指令,如果一条 CPU 指令是 8 byte 的话,那么 32 位操作系统就需要通过 2 个指令周期才能完成指令的读取,而对应的 64 位操作系统因为一次能够读取 64 bit 内容,所以它在一个指令周期就能够读取指令。所以,理论上,64
位的操作系统是要比 32 位操作系统要快 1 倍。
但还有几个需要大家注意的地方是:
1. 64 位 CPU 机器可以安装 32 位操作系统,但效率自然跟 32 位操作系统一样。
2. 32 位 CPU 机器也可以安装 64 位操作系统。
3. 64 位 CPU 机器安装 64 位操作系统才最有效率,但跟软件优化也有关系。
不同的操作系统平台,给 C/C++ 基本数据类型变量分配的字节是不一样的。
32位编译器:
char :1个字节 char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器) short int : 2个字节 int: 4个字节 unsigned int : 4个字节 float: 4个字节 double: 8个字节 long: 4个字节 long long: 8个字节 unsigned long: 4个字节
64位编译器:
char :1个字节 char*(即指针变量): 8个字节 short int : 2个字节 int: 4个字节 unsigned int : 4个字节 float: 4个字节 double: 8个字节 long: 8个字节 long long: 8个字节 unsigned long: 8个字节
上面讲的是 C/C++ 在不同平台上的字节长度差别,但是对于 Java 而言,由于 Java 是跨平台语言,所以 JVM 表现下的基础数据字节长度其实都是一致的。
int:4 个字节。 short:2 个字节。 long:8 个字节。 byte:1 个字节。 float:4 个字节。 double:8 个字节。 char:2 个字节。 boolean:boolean属于布尔类型,在存储的时候不使用字节,仅仅使用 1 位来存储,范围仅仅为0和1,其字面量为true和false。
我们可以看到 Java 与 C/C++ 的基本数据类型字节长度有些不一致,所以涉及到网络通信交互或者是 JNI 开发时,数据的转换有时需要考虑下基础的字节长度。
本篇文章的主要内容是 Java 中的位操作,所以基础数据长度也是以 Java 中定义的为准。
原码 反码 补码
我们已经知道了一个 int 型数值是 4 个字节。每个字节有 8 位。但对于一个 int 或者其它整数类型如 (long)的数值而言还要注意的是,它的最高位是符号位。最高位为0表示正数。
最高位为1表示负数
原码 将一个数字转换成二进制就是这个数值的原码。
int a = 5; //原码 0000 0000 0000 0101 int b = -3; //原码 1000 0000 0000 0011
反码
分两种情况:正数和负数
正数 正数的反码就是原码。
负数 负数的反码是在原码的基础上,符号位不变 其它位都取反。
5 的原码:0000 0000 0000 0101 -3 的原码:1000 0000 0000 0011 -3 的反码:1111 1111 1111 1100
补码
仍然分正数和负数两种情况
正数 正数的补码就是原码。
负数 负数的补码在反码的基础上加1。
5 的补码:0000 0000 0000 0101 -3 的反码:1111 1111 1111 1100 -3 的补码: 1111 1111 1111 1101
计算机在进行数值运算的时候,是通过补码表示每个数值的。
比如
5 - 3 = 5 + ( -3 ) 相当于 0000 0000 0000 0101 + 1111 1111 1111 1101 = 1 0000 0000 0000 0010
最后的结果是1 0000 0000 0000 0010 这样的二进制,由于 int 类型只有 4 byte,所以最高位产生了溢出,进位 1 被丢弃。结果就变成了 0010 也就是 2,5 - 3 = 2 没有毛病。
位运算符 &、|、~、^、>>、<<
位运算符包含与运算符、或运算符、取反运算符、异或运算符、左移运算符和右移运算符。在下面的内容中,我将会一一讲解。需要注意的是,下面测试用的数据都是 int 类型,int 类型是 4 个字节长度,但是为了方便说明示例中用的数值我都用 1 个字节表示。希望不会给大家造成困扰。
& 与运算符
规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值都是 1,则结果值相应的 bit 就是 1,否则为 0.0 & 0 = 0, 0 & 1 = 0, 1 & 1 = 1
3 & 5 = 1 这是因为
0000 0011 & 0000 0101 = 0000 0001
按照规则,将两个数值按照低位到高位一一对齐运算,因为只有第 0 位都为 1,所以计算结果为 1.
| 或运算符
规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值只要 1 个为 1,则结果值相应的 bit 就是 1,否则为 0。0 | 0 = 0, 0 | 1 = 1, 1 | 1 = 1
3 | 5 = 7 这是因为
0000 0011 | 0000 0101 = 0000 0111
~ 取反运算符
规则 对操作数的每一位进行操作,1 变成 0,0 变成 1。~5 => 0000 0101 ~ => 1111 1010
^ 异或运算符
规则 两个操作数进行异或时,对于同一位上,如果数值相同则为 0,数值不同则为 1。1 ^ 0 = 1, 1 ^ 1 = 0, 0 ^ 0 = 0;
3 ^ 5 = 6,这是因为
0000 0011 ^ 0000 0101 = 0000 0110
值得注意的是 3 ^ 5 = 6,而 6 ^ 5 = 3
0000 0110 ^ 0000 0101 = 0000 0011
针对这个特性,我们可以将异或运算作为一个简单的数据加密的形式。比如,将一个mp4文件所有数值与一个种子数值进行异或得到加密后的数据,解密的时候再将数据与种子数值进行异或一次就可以了。
所以说异或运算可以作为简单的加解密运算算法。
>> 右移运算符
规则 a >> b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向右方向移动 b 位,符号位不变,高位空出来的位补数值 0。5 >> 1 ===> 0000 0000 0000 0101 >> 1 = 0000 0000 0000 0010 = 2 7 >> 2 ===> 0000 0000 0000 0111 >> 2 = 0000 0000 0000 0001 = 1 9 >> 3 ===> 0000 0000 0000 1001 >> 3 = 0000 0000 0000 0001 = 1 11 >> 2 ===> 0000 0000 0000 1011 >> 2 = 0000 0000 0000 0010 = 2
大家发现什么规律没有?a >> b = a / ( 2 ^ b ) ,所以 5 >> 1= 5 / 2 = 2,11 >> 2 = 11 / 4 = 2。
<< 左移运算符
规则 a << b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向左方向移动 b 位,符号位不变,低位空出来的位补数值 0。5 << 1 ===> 0000 0000 0000 0101 << 1 = 0000 0000 0000 1010 = 10 7 << 2 ===> 0000 0000 0000 0111 << 2 = 0000 0000 0001 1100 = 28 9 << 3 ===> 0000 0000 0000 1001 << 3 = 0000 0000 0100 1000 = 72 11 << 2 ===> 0000 0000 0000 1011 << 2 = 0000 0000 0010 1100 = 44
很明显就可以看出 a << b = a * (2 ^ b)
综合上面两个可以看到,如果某个数值(仅指正数,正数的原反补在计算机中一致;因为负数在计算机中以补码形式存在)右移 n 位,就相当于拿这个数值去除以 2 的 n 次幂。如果某个数值(正数/负数)左移 n 位,就相当于这个数值乘以 2 ^ n。
参考内容
32位机和64位机的区别及基本数据类型占字节数转载:https://juejin.im/entry/58f9b6118d6d8100588060d6
相关文章推荐
- C++与Java基本数据类型比较
- C++与Java基本数据类型比较
- java,c,c++ 语言之间基本数据类型的比较
- java和c/c++ 数据类型长度的比较
- C/C++与Java各数据类型所占字节数比较
- C/C++与Java各数据类型所占字节数的详细比较
- java和c/c++ 数据类型长度的比较
- C++与Java基本数据类型比较
- java,c,c++ 语言之间基本数据类型的比较
- C/C++与Java各数据类型所占字节数的详细比较
- C/Java/C++数据类型的比较
- C++与Java基本数据类型比较
- C++与Java基本数据类型比较
- java,c,c++ 语言之间基本数据类型的比较
- java,c,c++ 语言之间基本数据类型的比较
- C++与Java基本数据类型比较
- C# 与 C++ 数据类型比较及结构体转换
- 在JAVA中怎么比较Double类型数据的大小?
- [Android] Jni中C++和Java的数据类型的对应关系
- java c++ 基本数据类型