一 字符串转为二进制数据
如果明确使用UTF-8编码,字符串”中”中的字符数仍然是1,但是占用的字节数会根据编码方式不同而有所变化。
在UTF-8编码中,一个中文字符占用3个字节。因此,字符串”中”在UTF-8编码下占用的字节数是3。
下面是具体的处理代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package org.example;
import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets;
public class Main { public static void main(String[] args) throws UnsupportedEncodingException { String text = "中"; int charCount = text.length(); System.out.println("字符数:" + charCount); System.out.println("\r\n");
printArray(text, StandardCharsets.UTF_8.name()); System.out.println("\r\n");
printArray(text, StandardCharsets.US_ASCII.name()); System.out.println("\r\n");
printArray(text, "unicode"); System.out.println("\r\n");
printArray(text, "GB18030"); System.out.println("\r\n");
printArray(text, "GB2312"); System.out.println("\r\n");
printArray(text, "GBK"); System.out.println("\r\n"); }
private static void printArray(String text, String charsetName) throws UnsupportedEncodingException { byte[] bytes = text.getBytes(charsetName); System.out.println(charsetName + "编码下字节数:" + bytes.length); System.out.print(charsetName + "编码下字节数的二进制表示:"); for (byte b : bytes) { System.out.print(Integer.toBinaryString(b & 0xFF) + " "); } } }
|
java中字符的长度与编码方式无关,但是使用的字节数与编码方式有关。
注意上面数据输出时执行了& 0xFF
操作,原因参见后面章节。
二 二进制数据转为字符串
2.1 byte形式的二进制数据转为字符串
1 2 3 4 5 6 7 8 9 10
| public class Main {
public static void main(String[] args) { byte[] bytes = {(byte) 0b11100100, (byte) 0b10111000, (byte) 0b10101101}; String str = new String(bytes, StandardCharsets.UTF_8); System.out.println("转换后的字符串:" + str); } }
|
运行以上代码,输出如下:
以上代码使用String
类的构造方法,将字节数组以UTF-8编码格式转换为字符串。StandardCharsets.UTF_8
表示使用UTF-8编码。最后输出转换后的字符串”中”。
2.2 字符串形式的二进制数据转为字符串
将上面 “中”经过utf-8编码后的二进制数据 “11100100 10111000 10101101”转换回来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Main {
public static void main(String[] args) { String text = "11100100 10111000 10101101";
final String[] tokens = text.split(" "); List<Byte> byteList = new ArrayList<>();
for (String token : tokens) { byte data = (byte) Integer.parseInt(token, 2); byteList.add(data); }
byte[] bytes = new byte[byteList.size()];
for (int i = 0; i < byteList.size(); i++) { bytes[i] = byteList.get(i); } String str = new String(bytes, StandardCharsets.UTF_8); System.out.println("转换后的字符串:" + str); } }
|
代码运行结果为
三 java中数字转为16进制时为什么要先执行 & 0xFF 操作
在Java中,数字转换为16进制时,执行 & 0xFF
操作是为了确保结果是一个有效的8位无符号整数。
在Java中,整数类型是有符号的,即它们可以表示正数和负数。当将一个有符号整数转换为16进制时,如果不执行 & 0xFF
操作,那么结果可能会包含负号,或者超过16进制的有效范围。
执行 & 0xFF
操作可以将一个有符号整数的高24位清零,只保留低8位。由于无符号整数的范围是0到255(即16进制的00到FF),所以执行 & 0xFF
操作可以确保结果在有效的16进制范围内。
以下是一个示例,说明为什么要执行 & 0xFF
操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package org.example;
public class Main {
public static void main(String[] args) { int number = -1; String binaryString = Integer.toBinaryString(number); System.out.println(binaryString);
binaryString = Integer.toBinaryString(number & 0xFF); System.out.println(binaryString);
String hexString = Integer.toHexString(number); System.out.println(hexString);
hexString = Integer.toHexString(number & 0xFF); System.out.println(hexString);
int hexInt2 = Integer.parseInt("ff", 16);
System.out.println(Integer.parseInt("11111111", 2));
System.out.println(Integer.parseInt("ff", 16));
System.out.println(Integer.parseUnsignedInt(Integer.toBinaryString(-1), 2)); System.out.println(Long.parseLong(Integer.toBinaryString(-1), 2));
System.out.println(Long.parseUnsignedLong(Integer.toBinaryString(-1), 2)); } }
|
在第一个示例中,由于没有执行 & 0xFF
操作,转换结果包含了负号和32个字符,这是因为在转换为16进制时,Java将有符号整数视为32位整数。
在第二个示例中,执行了 & 0xFF
操作,结果只保留了低8位,所以转换结果是一个有效的16进制数字。
四 字符串形式的二进制数据转为十进制
将字符串 1111 1111 1111 1111 1111 1111 1111 1111 转换为十进制数据-1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package org.example;
import java.math.BigInteger;
public class Demo1 { public static void main(String[] args) {
String str = "1111 1111 1111 1111 1111 1111 1111 1111"; str = str.replaceAll("\\s", "");
BigInteger decimal = new BigInteger(str, 2); if (decimal.testBit(str.length() - 1)) {
BigInteger mask = BigInteger.ONE.shiftLeft(str.length()).subtract(BigInteger.ONE); decimal = decimal.xor(mask).add(BigInteger.ONE).negate(); }
System.out.println(decimal); } }
|
五 F&Q
5.1 Integer.parseInt(Integer.toBinaryString(-1), 2) 为什么会报错
Integer.parseInt(Integer.toBinaryString(-1), 2)
报错的原因是由于-1的二进制表示是32位的全1,而Integer.parseInt
方法默认只能处理31位以内的二进制数。因此,超出了其处理范围,导致报错。
5.2 为什么Long.parseLong(Integer.toBinaryString(-1), 2)输出值为4294967295
Long.parseLong(Integer.toBinaryString(-1), 2) 输出值为4294967295 的原因是由于-1的二进制表示是32位的全1,而32位的全1在补码表示中代表的是无符号整数的最大值,即2^32 - 1。而Long.parseLong方法可以处理64位的二进制数,所以能够正确地解析出4294967295这个值。