概述
本文主要介绍java的二进制处理和相关的底层基础问题探索
JAVA的基础数据类型8种
类型 | 位数 | 字节数 | 范围 |
---|---|---|---|
byte | 8位 | 1字节 | -128(-2^7) — 127(2^7 - 1 |
short | 16位 | 2字节 | -32768(-2^15)— 32767(2^15 - 1) |
int | 32位 | 4字节 | -2,147,483,648(-2^31) — -2,147,483,647(2^31 - 1) |
long | 64位 | 8字节 | 默认值0L |
float | 32位 | 4字节 | 默认值0.0f |
double | 64位 | 8字节 | 默认值0.0d |
boolean | 1位 | 无 | 默认值false |
char | 16位 | 2字节 | Unicode字符 \u0000(0) — \uffff(65535) |
位运算运算符
类型 | 计算方式 | 速记方式 |
---|---|---|
& | 10101010 & 01010101 = 00000000 | 有0为0,出现0则为0 |
| | 10101010 | 01010101 = 11111111 | 有1为1,出现1则为1 |
^ | 10101010 ^ 01010101 = 11111111 | 合2为1,出现不同则为1,相同则为0 |
~ | ~10101010 = 0101010101 | 1变为0,0变为1 |
<< | 10101010 << 0xFF | 左移0xFF位,右补0相当与*2 |
>> | 10101010 >> 0xFF | 有符号右移0xFF位,正数高位补0,负数补1 |
>>> | 10101010 >>> 0xFF | 无符号右移0xFF位,高位全部补0 |
基础类型说明
从上面我们可以发现JAVA和C的差异,C语言整数默认是signed有符号的,C语言中也可用unsigned 表示一个无符号值,JAVA整数都是有符号的,但也可通过一些方式表示无符号值。
如何用JAVA表示C语言的正确值
java提供了一种方式来表示 C的 unsigned int short等, 如何实现,对当前的数据进行&运算,和谁?
具体和谁需要看你的数据类型,0xff的二进制是1111 1111 (8bit)
public int getUnsignedByte (byte data){ //将data字节型数据转换为0~255 (0xFF 即BYTE),
return data & 0x0FF ; //int 4字节 32位 表示将高24位全部变为0,保留低8位原始值,变为有符号首位为0的值,相当于C的有符号值
}
public int getUnsignedByte (short data){ //将data字节型数据转换为0~65535 (0xFFFF 即WORD)。
return data & 0x0FFFF ; //int 4字节 32位 表示将高16位全部变为0,保留低16位原始值,变为有符号首位为0的值,相当于C的有符号值
}
public long getUnsignedIntt (int data){ //将int数据转换为0~4294967295 (0xFFFFFFFF即DWORD)。
return data & 0x0FFFFFFFF ; //long 8字节 64位 表示将高32位全部变为0,保留低32位原始值,变为有符号首位为0的值,相当于C的有符号值
}
负数的二进制
在计算机中,正数是以原码的形式存储的,而负数是以补码的形式存储的,负数的二进制需要该数正数按位取反的值再+1.
详解>>>预算符
负数int -20无符号右移:r = -20 >>> 2
注:数据类型默认为int 32位
-20://负数的二进制需要该数正数按位取反的值再+1.
源码:10000000 00000000 00000000 00010100
反码:11111111 11111111 11111111 11101011//反码后+1
补码:11111111 11111111 11111111 11101100
右移:00111111 11111111 11111111 11111011
结果:r = 1073741819
^交换 a b 值
a=a∧b;
b=b∧a;
c=a∧b;
大端模式和小端模式
大端模式:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
低地址 ——————–> 高地址
0x12 | 0x34 | 0x56 | 0x78小端模式:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
低地址 ——————–> 高地址
0x78 | 0x56 | 0x34 | 0x12常见的CPU字节序
Big Endian : PowerPC、IBM、Sun
Little Endian : x86、DEC
ARM既可以工作在大端模式,也可以工作在小端模式
JAVA和大部分的网络通讯协议都是使用Big-Endian的编码.常见文件的字节序
Adobe PS – Big Endian
BMP – Little Endian
DXF(AutoCAD) – Variable
GIF – Little Endian
JPEG – Big Endian
MacPaint – Big Endian
RTF – Little Endian读取存储数据的顺序
不管是大端还是小端模式,我们在读取和存储数据的时候一定都是从内存的低地址依次向高地址读取或写入。[ps这句话非常重要,请注意理解]
A内存地址 | A存储的值 |
---|---|
0x2000 4001 | 0x01 |
0x2000 4002 | 0x02 |
0x2000 4003 | 0x03 |
0x2000 4004 | 0x04 |
如果现在大端模式A传递此数据给B小端模式
A将内存中的值取出,取值由内存的低地址往高地址取值,由于大端模式的内存低位地址(即0X01)对应字节数组高位值,则字节数组最高位(最左边位)为[0x01,X,X,X],则传递值为0x1234。
B接收到字节数组在内存中存储的时候也是按照内存低地址往高地址开始依次存储,由于小端模式的内存低位地址(即0x04)对应字节数组低位值,则在B中内存存储的数据为:
B内存地址 | B存储的值 |
---|---|
0x8000 4001 | 0x04 |
0x8000 4002 | 0x03 |
0x8000 4003 | 0x02 |
0x8000 4004 | 0x01 |
B将内存中的值取出,取值由内存的低地址往高地址取值,则字节数组最低位(最右边位)为[X,X,X,0x1],则取出值为0x4321.
为什么在内存中同样的存储,取到的值不一样呢,因为此数组是4个字节,按照小端模式取出来的值则不一样,如果字节序一样则值相同,如果只是单字节,也是相同的,不需要关心顺序。
会发现数据由A传递给B后其显示的数据发生了翻天覆地的变化,这就是为啥在处理网络数据的时候要确定字节序的原因,必须保证A和B的字节序相同,如果不同,就需要使用字节序的转换函数。
如何理解JAVA的有符号 [1byte -128 - 127]
举个栗子:JAVA的一个byte8位表示为10000001, C语言的一个byte8位表示为10000001
这个byte在JAVA和C中代表了不同的值JAVA > -1 C > -129为什么?
因为JAVA作为有符号其左边第一位用来表示正负值,第一位为1表示为一个负数,其表示的实际值为-1,而C语言左边第一位仍然表示数值其值为2^7 + 1 = 129 ,java 则为-1.
异或加密和解密
/**
* xor 加密 key=xxxxxxxxxx
* @Description:
* @param data
* @return
*/
public byte[] xorEncode(byte[] data){
for(int i = 0; i < data.length; ++i){
data[i] ^= keyBytes[i%keyBytes.length];
}
return data;
}
/**
* xor 解密 key=1234567890
* @Description:
* @param data
* @return
*/
public byte[] xorDecode(byte[] data){
for(int i = 0; i < data.length; ++i){
data[i] ^= keyBytes[i%keyBytes.length];
}
return data;
}
JAVA byte[] TO short 的大小端和无符号相互转换
/**
* @功能 字节的转换与短整型 小端模式
* @param 两位的字节数组
* @return 短整型
*/
public short byteToShort(byte[] b) {
short s = 0;
short s0 = (short) (b[0] & 0xff);// 最低位
short s1 = (short) (b[1] & 0xff);
s1 <<= 8; //byte数组低位值左移8位
s = (short) (s0 | s1);
return s;
}
/**
* @功能 字节的转换与短整型 大端模式
* @param 两位的字节数组
* @return 短整型
*/
public short byteToShort_BIG(byte[] b) {
short s = 0;
short s0 = (short) (b[1] & 0xff);// 最低位
short s1 = (short) (b[0] & 0xff);
s1 <<= 8; //byte数组低位值左移8位
s = (short) (s0 | s1);
return s;
}
/**
* @功能 字节转换为短整型 无符号short
* @param 两位的字节数组
* @return 短整型
*/
public int byteToUnSinghedShort(byte[] b) {
short s = 0;
short s0 = (short) (b[0] & 0xff);// 最低位
short s1 = (short) (b[1] & 0xff);
s1 <<= 8; //byte数组低位值左移8位
s = (short) (s0 | s1);
return s & 0xFFFF; // short 所以和0xFFFF做&运算
}
/**
* @功能 短整型与字节数组的转换 小端模式
* @param 短整型
* @return 两位的字节数组
*/
public byte[] shortToByte(short number) {
int temp = number;
byte[] b = new byte[2];
for (int i = 0; i < b.length; i++) {
b[i] = new Integer(temp & 0xff).byteValue();// 将最低位保存在最低位
temp = temp >> 8; // 向右移8位
}
return b;
}
/**
* @功能 短整型与字节数组的转换 大端模式
* @param 短整型
* @return 两位的字节数组
*/
public byte[] shortToByte_Big(short number) {
int temp = number;
byte[] b = new byte[2];
for (int i = 0; i < b.length; i++) {
b[b.length - i - 1] = new Integer(temp & 0xff).byteValue();// 将最低位保存在最高位
temp = temp >> 8; // 向右移8位
}
return b;
}
一盏灯, 一片昏黄; 一简书, 一杯淡茶。 守着那一份淡定, 品读属于自己的寂寞。 保持淡定, 才能欣赏到最美丽的风景! 保持淡定, 人生从此不再寂寞。