整理一下二进制、计算机编码、位运算相关知识,拒绝含糊不清
主要设计三个基本数据类型 byte、int、char
以16进制表示查看二进制文件
xxd file
反码、补码:
https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
上面虽然解释了 反码,补码,但是还是有一些问题没有解释清楚:为什么负数的补码是反码+1,为什么正数的补码还是本身,-128的补码为什么是10000000等等,请看下面👇
https://www.cnblogs.com/esmusssein/p/11182321.html
字符编码:
https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
Java 判断本地主机字节序工具:ByteOrder.nativeOrder();
大端小端在一台机器上没感知,因为高位地位是确定的,只不过在有的机器上内存的高地址对应高位叫“小端字节序” 像x86架构,而有的是内存的高地址对应低位叫“大端字节序”。
Unicode 编码查询工具:
https://www.qqxiuzi.cn/bianma/Unicode-UTF.php
Java内码是utf-16吗?
https://blog.csdn.net/u014631304/article/details/77509380
关于Unicode更多理解:
https://www.jianshu.com/p/ad4bff4d9fa3
Java编码扩展知识:
https://www.jianshu.com/p/1b00ca07b003
理解byte负数:
https://blog.csdn.net/csdn_ds/article/details/79106006
& 0xff 获取真值原理:
https://blog.csdn.net/i6223671/article/details/88924481
常用工具代码:
- byte 转 二进制表示
/**
* byte 转 二进制表示
* @param b
* @return
*/
public static String byteToBit(byte b) {
return ""
+ (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
}
- 获取byte指定位的值
/**
* 获取byte指定位的值
* @param b
* @param i (i>=1)
* @return
*/
public static byte getBitArray(byte b,int i) {
return (byte) ((b >> (8-i)) & 0x1);
}
- 字节数组转16进制
/**
* 字节数组转16进制
* @param bytes 需要转换的byte数组
* @return 转换后的Hex字符串
*/
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if(hex.length() < 2){
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}
- char 转 byte数组(JVM大端转化的结果,非真实内存存放顺序)
/**
* char 转 byte数组
* @param c
* @return
*/
public static byte[] charToByte(char c) {
byte[] b = new byte[2];
b[0] = (byte) ((c & 0xFF00) >> 8);
b[1] = (byte) (c & 0xFF);
return b;
}
- 16进制 转 字节数组
/**
* 16进制 转 字节数组
* @param hexString
* @return
*/
public static byte[] hexString2Bytes(String hexString) {
BiFunction<Byte, Byte, Byte> uniteBytes = (src0, src1) -> {
char b0 = (char) Byte.decode("0x" + new String(new byte[] {src0})).byteValue();
b0 = (char) (b0 << 4);
char b1 = (char) Byte.decode("0x" + new String(new byte[] {src1})).byteValue();
return (byte) (b0 ^ b1);
};
int size = hexString.length();
byte[] ret = new byte[size / 2];
byte[] tmp = hexString.getBytes();
for (int i = 0; i < size / 2; i++) {
ret[i] = uniteBytes.apply(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
- byte数组 转 int
/**
* byte数组 转 int
* @param bytes
* @return
*/
public static int bytes2Int(byte[] bytes) {
int result = 0;
//将每个byte依次搬运到int相应的位置
result = bytes[0] & 0xff;
result = result << 8 | bytes[1] & 0xff;
result = result << 8 | bytes[2] & 0xff;
result = result << 8 | bytes[3] & 0xff;
return result;
}
- int 转 byte数组
/**
* int 转 byte数组
* @param num
* @return
*/
public static byte[] int2Bytes(int num) {
byte[] bytes = new byte[4];
//通过移位运算,截取低8位的方式,将int保存到byte数组
bytes[0] = (byte) (num >>> 24);
bytes[1] = (byte) (num >>> 16);
bytes[2] = (byte) (num >>> 8);
bytes[3] = (byte) num;
return bytes;
}
- 获取String内存中对应的 UTF-16 编码的byte数组 (JVM大端转化的结果,非真实内存存放顺序)
/**
* 获取String内存中对应的 UTF-16 编码的byte数组
* @param str
* @return
*/
public static byte[] string2bytes(String str) {
ByteBuffer heapByteBuffer = ByteBuffer.allocate (str.length() * 2);
for (char c : str.toCharArray()) {
heapByteBuffer.putChar(c);
}
heapByteBuffer.flip();
int len = heapByteBuffer.limit() - heapByteBuffer.position();
byte[] bytes = new byte[len];
heapByteBuffer.get(bytes);
return bytes;
}
- 通过Unsafe查看字符在内存中的实际顺序(非JVM优化过的,我认为这才是内存真实存放的顺序,取决于具体的CPU架构)
@SuppressWarnings("restriction")
static private sun.misc.Unsafe getUnsafe() throws IllegalArgumentException, IllegalAccessException {
Class<?> cls = sun.misc.Unsafe.class;
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
if ("theUnsafe".equals(f.getName())) {
f.setAccessible(true);
return (sun.misc.Unsafe) f.get(null);
}
}
throw new IllegalAccessException("no declared field: theUnsafe");
}
/**
* 查看字符在内存中真实的顺序,非JVM优化的,取决于CPU架构
* @param ch
* @return
* @throws IllegalAccessException
*/
public static byte[] char2bytesNative(char ch) throws IllegalAccessException {
byte[] bytes = new byte[2];
Unsafe unsafe = getUnsafe();
long address = unsafe.allocateMemory(2);
unsafe.putChar(address, ch);
byte b = unsafe.getByte(address);
bytes[0] = b;
b = unsafe.getByte(address + 1);
bytes[1] = b;
return bytes;
}
public static void main(String[] args) throws Throwable {
System.out.println(bytes2HexString(charToByte('国')));
System.out.println(bytes2HexString(char2bytesNative('国')));
}
/**
* 还有一种更直接的方法
* @param ch
* @return
* @throws IllegalAccessException
*/
public static byte[] char2bytesNative2(char ch) throws IllegalAccessException {
Unsafe unsafe = getUnsafe();
char[] charArr = new char[1];
charArr[0] = ch;
byte b = unsafe.getByte(charArr, (long) (unsafe.arrayBaseOffset(charArr.getClass())));
byte[] bytes = new byte[2];
bytes[0] = b;
b = unsafe.getByte(charArr, (long) (unsafe.arrayBaseOffset(charArr.getClass()) + 1));
bytes[1] = b;
return bytes;
}