文章

进制

进制

进制互转

十进制转二、八、十六进制

1
2
3
4
5
6
7
8
9
public static void decimalTo(int num) {
    System.out.println("十进制:" + num);
    String s = Integer.toBinaryString(num);
    String s1 = Integer.toOctalString(num);
    String s2 = Integer.toHexString(num);
    System.out.println("二进制:" + s);
    System.out.println("八进制:" + s1);
    System.out.println("十六进制:" + s2);
}

结果:

1
2
3
4
十进制:10
二进制:1010
八进制:12
十六进制:a

二、八、十六进制转十进制

1
2
Integer.parse(s, radix) // 二进制超过32位,会异常
Integer.parse(s, parseUnsignedInt) // 转32位的二进制,不会异常,会通过Long.parseLong,会丢失精度

十六进制(Hex)与 byte 数组之间的转换

十六进制(Hex):计算机中数据的一种表示方法,它由 0-9,A-F 组成,字母不区分大小写。与 10 进制的对应关系是:0-9 对应 0-9;A-F 对应 10-15。

字节(byte):   Java 中一个 byte 为 8 个 bit 位。

转换原理:

1
2
3
4
每个二进制位有两种状态,分别为0,1
因此,两个二进制位有4种状态,分别为:00,01,10,11
三个二进制位有8种状态,分别为000,001,010,011,100,101,110,111
四个二进制位有十六种状态,0000,0001......1110,1111.   即十六进制

一个十六进制数(Hex),正好为 4 个二进制位。一个字节(byte)为 8 个二进制位。因此,一个字节可表示为两个十六进制数字。

因此,我们可以将一个 byte 用两个 Hex 表示,同理,我们也可以将两个 Hex 转换为一个 byte。

byte 转十六进制

1
2
3
4
5
6
7
8
9
10
11
/**
 * 1个byte有8个bit,每4个bit能表示1个十六进制数,1个byte能表示2个十六进制数
 */
private static String byteToHex(byte b) {
    System.out.println("byte:" + b);
    int i = b & 0xFF;
    System.out.println("0xFF:" + i);
    String s = Integer.toHexString(i);
    System.out.println("十六进制:" + s);
    return s;
}

结果:

1
2
3
4
5
6
7
int num = 10;
decimalTo(num);

十进制10
二进制1010
八进制:12
十六进制a

byte 数组转十六进制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 字节数组转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();
}

结果:

1
2
3
// 33 = 0010 0001 = 16+16+1 = 10+10+1
byte[] bytes = {11, 2, 33, 4, 56, 15, 16};// 0B 02 21 04 38 0f 10
System.out.println(bytesToHex(bytes));

Integer parseInt 和 parseUnsignedInt 区别

把一个 32 位的二进制字符串转成一个整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
String binary = "11000000101010000000000100000001"; // 超过32位
long l = Long.parseLong(binary, 2);
System.out.println("Integer.MAX_VALUE:" + Integer.MAX_VALUE);
System.out.println("Long:" + l);
System.out.println((int) l);
int ipnum = Integer.parseUnsignedInt(binary, 2); // Int溢出了
System.out.println(ipnum);
int ipnum2 = Integer.parseInt(binary, 2); // 出错
System.out.println(ipnum2);

结果
Integer.MAX_VALUE:2147483647
Long:3232235777
int转为long-1062731519
parseUnsignedInt-1062731519
Exception in thread "main" java.lang.NumberFormatException: For input string: "11000000101010000000000100000001"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:583)
	at com.example.javalib.进制.进制.main(进制.java:25)

parseInt 和 parseUnsignedInt 主要区别不是有无符号,parseUnsignedInt 是 JDK1.8 新增,parseUnsignedInt 会进行 Long.parseLong 判断,但转换的数超出了 int 范围,所以溢出了。

1
2
3
4
5
6
7
8
long ell = Long.parseLong(s, radix);
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
    return (int) ell;
} else {
    throw new
        NumberFormatException(String.format("String value %s exceeds " +
                                            "range of unsigned int.", s));
}

二进制位 11000000101010000000000100000001,long 为 3232235777,

转为 int 时,溢出了,保留最后 32 位,

由于计算机中,都是以补码的方式存储,最后一位为符号位,1 表示负数,0 表示正数,

11000000101010000000000100000001 的原码为 00111111010101111111111011111111

对应的十进制为:-1062731519

补码转原码规则:
注意:正数的原码反码和补码都是一样的,也就是说正数没有原码反码补码一说
而负数,补码变原码:符号位保持不变,从后往前开始,保持第一个 1 不变,后面的按位取反,直到符号位

本文由作者按照 CC BY 4.0 进行授权