消息队列篇--扩展篇--码表及编码解码(理解字符字节和二进制,了解ASCII和Unicode,了解UTF-8和UTF-16,了解字符和二进制等具体转化过程等)
1、理解字符,int,字节以及二进制存储
(1)、字符
字符是文本的基本单位,例如字母(A, B, C)、数字(1, 2, 3)、标点符号(!, ?, ,)以及其他符号(如特殊符号😊等)。
编码表示:
在计算机中,字符通过编码标准(如ASCII、Unicode)映射为特定的数值(称为“码点”或“代码点”)。
例如:
- 'A’的ASCII码点是65(ASCII)或U+0041(Unicode)。
- '你’的Unicode码点是U+4F60(Unicode)。
存储与处理:
字符为字符串的一部分,但也可以单独处理。例如,在Java中,字符用char类型表示,每个char占用2字节(UTF-16编码)。
示例:
char ch = 'A'; // 'A'的Unicode码点是U+0041
System.out.println((int) ch); // 输出65
(2)、基本数据类型int
int是Java中的一种基本数据类型,用于表示整数。它占用4字节(32 位),可以表示的范围是从-2,147,483,648到2,147,483,647。
用途:
int类型常用于数值计算、索引数组、计数等场景。它可以存储较大的整数值,适合大多数常见的数值运算。
示例:
char ch = 'A';
int codePoint = (int) ch; // 将字符'A'转换为其Unicode码点65
System.out.println(codePoint); // 输出65
(3)、字节(Byte)
字节(byte)是计算机中最小的可寻址数据单位,通常由8位(bit)组成。一个字节可以表示的范围是从0到255(无符号)或从-128到127(有符号)。
用途:
字节广泛用于文件读写、网络传输、内存操作等场景。它是计算机中最基本的数据存储单元。
示例:
byte b = 65; // 字节值65
System.out.println(b); // 输出65
字节与字符的关系:
字符在计算机中最终以字节形式存储。不同编码方式(如UTF-8、UTF-16)决定了如何将字符映射为字节序列。
例如:
- 'A’在UTF-8中表示单个字节65,在UTF-16中会开辟两个字节存储。
- '你’在UTF-8中表示为三个字节E4 BD A0。
示例:
String str = "你好";
byte[] utf8Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_8);
for (byte b : utf8Bytes) {
System.out.printf("%02X ", b); // 输出十六进制展示: E4 BD A0 E5 A5 BD
}
(4)、计算机中的二进制数据
二进制数据是计算机内部表示信息的基本方式,所有数据最终都以二进制形式存储和处理。二进制数据由一系列的位(bit)组成,每个位可以是0或1。
数据类型与二进制表示:
不同的数据类型在计算机中以不同的方式存储为二进制数据。
- 字符:通过编码标准(如UTF-8、UTF-16)转换为字节序列,每个字节由8位组成。
- 整数:直接存储为二进制形式。例如,整数65在二进制中表示为00000000 00000000 00000000 01000001(32位,因为一个int占用4个字节存储)。
示例:
int number = 65;
System.out.println(Integer.toBinaryString(number)); // 输出1000001
示例1:字符与二进制数据
假设我们有一个字符’A’,其Unicode码点是65。我们可以将其转换为二进制形式。
char ch = 'A';
int codePoint = (int) ch; // 获取 Unicode 码点
String binaryString = Integer.toBinaryString(codePoint);
System.out.println("Binary representation of 'A': " + binaryString); // 输出1000001
示例2:整数与二进制数据
假设我们有一个整数65,我们可以查看其二进制表示。
int number = 65;
String binaryString = Integer.toBinaryString(number);
System.out.println("Binary representation of 65: " + binaryString); // 输出 1000001
(5)、总结
- 字符是文本的基本单位,通过编码标准(如ASCII、Unicode)映射为特定的数值(码点)。字符在计算机中通常存储为字符串的一部分,但也可以单独处理。
- int是一种基本数据类型,用于表示整数,占用4字节(32位),适用于数值计算、索引数组等场景。字符可以通过强制转换为int来获取其对应的Unicode码点。
- 字节是计算机中最小的可寻址数据单位,由8位组成。字符在计算机中最终以字节形式存储,不同编码方式决定了如何将字符映射为字节序列。
- 二进制数据是计算机内部表示信息的基本方式,所有数据最终都以二进制形式存储和处理。不同数据类型在计算机中以不同的方式存储为二进制数据。
2、ASCII和Unicode
ASCII和Unicode是两种字符集编码标准,它们在设计目的、字符集范围和应用场合上有显著的区别。
(1)、ASCII (American Standard Code for Information Interchange)
1、定义与用途
ASCII是一种早期的字符编码标准,主要用于表示英文字母、数字和一些常见的符号。
- 用途:它广泛应用于早期的计算机系统中,特别是在美国和英语国家。
- 范围:ASCII定义了128个字符(从0到127),每个字符用一个字节(8位)中的低7位表示(最高位通常为0)。
2、字符集
基本字符:
- 控制字符:如换行(LF, U+000A)、回车(CR, U+000D)等不可见字符。
- 可打印字符:包括大写和小写字母(A-Z, a-z)、数字(0-9)、标点符号和其他常见符号(如 !, @, , $, % 等)。
3、编码方式
固定长度编码:每个字符占用1字节(8位),但只使用了低7位,因此实际上只用了7位(最高位为0)。
示例:
- 'A’的ASCII编码是41(十六进制)或01000001(二进制)。
- '!'的ASCII编码是21(十六进制)或00100001(二进制)。
完整ASCII码表:
(2)、Unicode
1、定义与用途
Unicode是一个全球通用的字符集标准,旨在为世界上几乎所有的书写系统中的每个字符分配一个唯一的编号(称为“码点”或“代码点”)。
- 用途:Unicode被设计用来解决不同语言和地区之间的字符编码问题,支持几乎所有现代语言以及许多历史上的语言和符号。
- 范围:Unicode包含超过140,000个字符,覆盖了从基本拉丁字母到复杂的象形文字等各种字符。
2、字符集
- 基本多文种平面(BMP):包含最常见的字符,范围从U+0000到U+FFFF,涵盖了大多数常用字符。
- 补充平面:用于表示超出BMP的字符,范围从U+10000到U+10FFFF,包括表情符号、古代文字等。
3、编码方式
变长编码:Unicode本身并不是一种具体的编码格式,而是通过UTF-8、UTF-16等具体编码格式来实现。
- UTF-8:变长编码,兼容ASCII。对于单字节字符(如英文字符),UTF-8使用1字节;对于多字节字符(如中文字符),UTF-8可能使用2到4字节。
- UTF-16:变长编码,主要使用2字节表示BMP中的字符,对于超出BMP的字符使用4字节(代理对)。
(3)、主要区别
(4)、示例对比
1、ASCII字符
假设我们有一个简单的ASCII字符串"Hello!"。
ASCII编码结果:
‘H’ -> 48(十六进制)或01001000(二进制)
‘e’ -> 65(十六进制)或01100101(二进制)
‘l’ -> 6C(十六进制)或01101100(二进制)
‘o’ -> 6F(十六进制)或01101111(二进制)
‘!’ -> 21(十六进制)或00100001(二进制)
2、Unicode字符
假设我们有一个包含中文字符的字符串"你好"。
Unicode码点:
‘你’ -> U+4F60
‘好’ -> U+597D
UTF-8编码:
‘你’ -> E4 BD A0(三字节)
‘好’ -> E5 A5 BD(三字节)
UTF-16编码:
‘你’ -> 4F60(两字节)
‘好’ -> 597D(两字节)
(5)、Java示例
1、ASCII字符编码
public class AsciiExample {
public static void main(String[] args) {
String originalString = "Hello!";
// 使用 ASCII 编码将字符串转换为字节数组
byte[] asciiBytes = originalString.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
System.out.println("Encoded with ASCII:");
for (byte b : asciiBytes) {
System.out.printf("%02X ", b);
}
}
}
输出示例:
Encoded with ASCII:
48 65 6C 6C 6F 21
2、Unicode字符编码
import java.nio.charset.StandardCharsets;
public class UnicodeExample {
public static void main(String[] args) {
String originalString = "你好";
// 使用 UTF-8 编码将字符串转换为字节数组
byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
System.out.println("Encoded with UTF-8:");
printByteArray(utf8Bytes);
// 使用 UTF-16 编码将字符串转换为字节数组
byte[] utf16Bytes = originalString.getBytes(StandardCharsets.UTF_16);
System.out.println("Encoded with UTF-16:");
printByteArray(utf16Bytes);
}
private static void printByteArray(byte[] bytes) {
for (byte b : bytes) {
System.out.printf("%02X ", b);
}
System.out.println();
}
}
输出示例:
Encoded with UTF-8:
E4 BD A0 E5 A5 BD
Encoded with UTF-16:
FE FF 4F 60 59 7D
(6)、ASCII和Unicode总结
- ASCII是一种早期的字符编码标准,仅支持128个字符,主要用于表示英文字母、数字和一些常见的符号。它的优点是简单且高效,但只能处理有限的字符集。
- Unicode是一个全球通用的字符集标准,旨在为世界上几乎所有的书写系统中的每个字符分配一个唯一的编号。它通过UTF-8、UTF-16等具体编码格式实现,能够支持多种语言和符号,适用于现代计算机系统中的多语言文本处理。
通过理解这些区别,你可以根据实际需求选择合适的字符编码方式。对于纯英文文本,ASCII或UTF-8都是非常高效的选择;而对于多语言文本,UTF-8或UTF-16更加适合。
3、UTF-8、UTF-16和Base64
UTF-8和UTF-16是Unicode字符集的具体编码实现,用于将Unicode码点转换为字节序列以便在计算机系统中存储和传输。
Base64是一种二进制到文本的编码方法,主要用于将任意二进制数据转换为ASCII字符串格式。
(1)、UTF-8编码
UTF-8是一种变长编码格式,兼容ASCII。可以根据字符的不同范围使用不同数量的字节来表示Unicode码点。UTF-8可以使用1到4字节来表示不同的字符。
变长编码理解下:
如UTF-8是一种变长编码格式,这意味着它可以根据字符的不同范围使用不同数量的字节来表示Unicode码点。
固定长度的编码格式:
与变长编码相对应的是固定长度的编码格式,这些编码方式对每个字符使用相同数量的字节进行表示。常见的固定长度编码方式有ASCII编码、UTF-32等。UTF-32每个字符占用4字节,能够表示所有Unicode码点,但占用更多存储空间;ASCII每个字符占用1字节,仅支持128个字符,主要用于英语和西欧语言。
对比:
具体规则:
单字节字符(ASCII字符):
- 范围:U+0000到U+007F
- 示例:‘A’ (U+0041)在UTF-8中表示为41(1字节)
双字节字符:
- 范围:U+0080到U+07FF
- 示例:‘é’ (U+00E9)在UTF-8中表示为C3 A9(2字节)
三字节字符:
- 范围:U+0800到U+FFFF
- 示例:‘你’ (U+4F60)在UTF-8中表示为E4 BD A0(3字节)
四字节字符:
- 范围:U+10000到U+10FFFF
- 示例:表情符号😊(U+1F60A)在UTF-8中表示为F0 9F 98 8A(4字节)
示例代码:
import java.nio.charset.StandardCharsets;
public class Utf8Example {
public static void main(String[] args) {
// 字符 '你'
String bmpStr = "你";
byte[] utf8BytesBmp = bmpStr.getBytes(StandardCharsets.UTF_8);
System.out.println("BMP character: " + bmpStr);
System.out.print("UTF-8 encoding (hex): ");
for (byte b : utf8BytesBmp) {
System.out.printf("%02X ", b);
}
System.out.println();
// 补充平面字符 😊
String emojiStr = "😊";
byte[] utf8BytesEmoji = emojiStr.getBytes(StandardCharsets.UTF_8);
System.out.println("Supplementary character: " + emojiStr);
System.out.print("UTF-8 encoding (hex): ");
for (byte b : utf8BytesEmoji) {
System.out.printf("%02X ", b);
}
System.out.println();
}
}
输出示例:
BMP character: 你
UTF-8 encoding (hex): E4 BD A0
Supplementary character: 😊
UTF-8 encoding (hex): F0 9F 98 8A
(2)、UTF-16编码
UTF-16是一种变长编码格式,主要用于将Unicode码点转换为字节序列。它主要使用16位(2字节)来表示Unicode的基本多文种平面(BMP,Basic Multilingual Plane),即从U+0000到U+FFFF范围内的字符。对于超出BMP的字符(即从U+10000到U+10FFFF),UTF-16使用32位(4字节)表示,通过所谓的“代理对”(surrogate pairs)实现。
具体规则:
BMP字符:
- 对于码点在U+0000到U+FFFF范围内的字符,UTF-16直接只用两个字节,即一个16位二进制值来表示。
- 例如,字符’你’的Unicode码点是U+4F60,在UTF-16中直接表示为4F60。
补充平面字符:
- 对于码点在U+10000到U+10FFFF范围内的字符,UTF-16使用4个字节即2个16位二进制值(称为“代理对”)来表示。
- 这两个16位值分别是一个高代理(High Surrogate)和一个低代理(Low Surrogate)。
- 高代理范围:D800到DBFF
- 低代理范围:DC00到DFFF
- 例如,表情符号😊的Unicode码点是U+1F60A,在UTF-16中表示为两个char:高代理D83D和低代理DE0A。
示例代码:
public class Utf16Example {
public static void main(String[] args) {
// BMP字符 '你'
char bmpChar = '\u4F60'; // U+4F60
System.out.println("BMP character: " + bmpChar);
System.out.println("UTF-16 encoding (hex): " + Integer.toHexString(bmpChar));
// 补充平面字符 😊
String emoji = "\ud83d\ude0a"; // U+1F60A
System.out.println("Supplementary character: " + emoji);
for (int i = 0; i < emoji.length(); i++) {
System.out.printf("UTF-16 encoding (hex): %04X\n", (int) emoji.charAt(i));
}
}
}
输出示例:
BMP character: 你
UTF-16 encoding (hex): 4F60
Supplementary character: 😊
UTF-16 encoding (hex): D83D
UTF-16 encoding (hex): DE0A
和UTF-8区别:
(3)、Base64
Base64是一种二进制到文本的编码方法,主要用于将任意二进制数据转换为ASCII字符串格式。它广泛应用于电子邮件附件、URL编码、HTTP基本认证等领域。
目的:
确保二进制数据能够在只支持文本的环境中安全传输,例如通过电子邮件或HTTP请求传递。
工作原理:
-
编码过程:Base64将每3个字节(24位)的二进制数据分成4组,每组6位,并将每个6位值映射到一个Base64字符表中的字符(共64个字符:A-Z, a-z, 0-9, +, /)。如果输入的数据不是3的倍数,则会在末尾添加填充字符=。
-
解码过程:将Base64编码的字符串还原为原始的二进制数据。
示例:
假设我们有一段二进制数据Hello。
import java.util.Base64;
public class Base64Example {
public static void main(String[] args) {
String originalString = "Hello";
// 使用Base64编码
String encodedString = Base64.getEncoder().encodeToString(originalString.getBytes());
System.out.println("Encoded with Base64: " + encodedString);
// 使用Base64解码
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes);
System.out.println("Decoded from Base64: " + decodedString);
}
}
输出示例:
Encoded with Base64: SGVsbG8=
Decoded from Base64: Hello
(4)、区别总结
(5)、具体应用场景
1、UTF-8
- 网页内容:大多数现代网页使用UTF-8编码来显示各种语言的文本。
- 文件存储:许多文本文件(如HTML、CSS、JavaScript文件)默认使用UTF-8编码。
2、UTF-16
- 编程语言内部表示:Java和C等编程语言使用UTF-16作为其字符串的内部表示。
- 数据库存储:某些数据库系统也支持UTF-16编码。
3、Base64
- 电子邮件附件:由于SMTP协议最初设计时并未考虑二进制数据的传输,因此Base64编码被广泛用于将附件转换为文本格式进行传输。
- URL编码:在URL中传递二进制数据时,Base64编码可以确保数据不会被误解为URL特殊字符。
- HTTP基本认证:用户名和密码在HTTP基本认证中通常使用Base64编码后传递。
(6)、示例代码对比
UTF-8和UTF-16编码示例:
import java.nio.charset.StandardCharsets;
public class EncodingExample {
public static void main(String[] args) {
String originalString = "你好";
// UTF-8 编码
byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
System.out.println("Encoded with UTF-8:");
printByteArray(utf8Bytes);
// UTF-16 编码
byte[] utf16Bytes = originalString.getBytes(StandardCharsets.UTF_16);
System.out.println("Encoded with UTF-16:");
printByteArray(utf16Bytes);
}
private static void printByteArray(byte[] bytes) {
for (byte b : bytes) {
System.out.printf("%02X ", b);
}
System.out.println();
}
}
输出示例:
Encoded with UTF-8:
E4 BD A0 E5 A5 BD
Encoded with UTF-16:
FE FF 4F 60 59 7D
Base64编码示例:
import java.util.Base64;
public class Base64Example {
public static void main(String[] args) {
String originalString = "Hello, World!";
// 使用 Base64 编码
String encodedString = Base64.getEncoder().encodeToString(originalString.getBytes());
System.out.println("Encoded with Base64: " + encodedString);
// 使用 Base64 解码
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes);
System.out.println("Decoded from Base64: " + decodedString);
}
}
输出示例:
Encoded with Base64: SGVsbG8sIFdvcmxkIQ==
Decoded from Base64: Hello, World!
总结:
- UTF-8和UTF-16是用于将Unicode码点转换为字节序列的编码方式,适用于文本数据的存储和传输。UTF-8兼容ASCII,适合纯英文文本和多语言混合文本,而UTF-16主要用于编程语言内部表示和某些数据库系统。
- Base64是一种二进制到文本的编码方法,用于将任意二进制数据转换为ASCII字符串,以确保数据能够在只支持文本的环境中安全传输。它广泛应用于电子邮件附件、URL编码和HTTP基本认证等场景。
4、字符串和二进制转换
在计算机系统中,字符串转换为二进制(编码)和从二进制还原为字符串(解码)的过程是通过字符编码标准来实现的。常见的字符编码标准包括ASCII、UTF-8、UTF-16等。这些编码标准定义了如何将字符映射到二进制表示。
(1)、字符串转二进制(编码)
编码过程是将字符串中的每个字符转换为其对应的二进制表示。不同的字符编码标准有不同的规则。
例如:
- ASCII:每个字符用7位或8位表示(实际使用8位,其中一位通常为0)。
- UTF-8:可变长度编码,单字节字符用1字节表示,其他字符可能需要2到4字节。
- UTF-16:可变长度编码,基本多文种平面(BMP)中的字符用2字节表示,其他字符用4字节表示。(Java使用UTF-16编码来表示字符,char类型占用2字节,超出BMP的字符使用代理对表示。)
简单说明下:
对于字母‘A’,如果使用ASCII编码,仅会开一个字节的空间。如果使用UTF-8编码,也是会仅开辟一个字节的存储空间(UTF-8完全兼容ASCII码)。如果使用UTF-16编码,会开辟2个字节的空间来存储。
字符串转换为二进制的过程通常分为两个主要步骤:
1、根据编码方式将字符串转换为字节数组
- 字符串中的每个字符首先根据指定的编码方式(如UTF-8、UTF-16或ASCII)转换为相应的字节序列。不同的编码方式会生成不同长度和格式的字节数组。
2、将字节数组转换为二进制表示 - 每个字节可以进一步表示为一个8位的二进制数。因此,字节数组可以直接映射为一系列的二进制位。
代码示例:
import java.nio.charset.StandardCharsets;
public class StringToBinaryExample {
public static void main(String[] args) {
// 原始字符串
String originalString = "Hello, World!";
// 使用 UTF-8 编码将字符串转换为字节数组(二进制)
byte[] encodedBytes = originalString.getBytes(StandardCharsets.UTF_8);
// 打印字节数组
System.out.println("Encoded bytes (in hex):");
for (byte b : encodedBytes) {
System.out.printf("%02X ", b); // 16进制输出,X输出大写,x输出小写
}
System.out.println();
// 可选:打印每个字节的二进制表示
System.out.println("Encoded bytes (in binary):");
for (byte b : encodedBytes) {
System.out.printf("%8s ", Integer.toBinaryString(b & 0xFF));
}
System.out.println();
}
}
输出示例:
Encoded bytes (in hex):
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
Encoded bytes (in binary):
01001000 01100101 01101100 01101100 01101111 00101100 00100000 01010111 01101111 01110010 01101100 01100100 00100001
解释:
原始字符串Hello, World!包含13个字符,且都是普通ASCII字符,所以在UTF-8编码后仅开辟了13个字节存储。
(2)、二进制还原为字符串(解码)
解码过程是将二进制数据转换回原始字符串。这需要知道原始字符串使用的字符编码标准(ASCII,UTF-8或UTF-16),以便正确地解释二进制数据。
以UTF-8为例说明:
在将二进制数据还原为字符串时,特别是使用UTF-8编码的情况下,确实需要特别注意其变长特性。UTF-8是一种变长编码格式,字符的长度可以从1到4字节不等。因此,解析UTF-8编码的二进制数据时,需要根据每个字节的前几位来判断该字符占用多少个字节。
步骤概述:
1、读取字节流:从二进制数据中逐字节读取。
2、识别字节类型。
原则:根据字节的前几位确定该字节是单字节字符还是多字节字符的一部分。
3、组合字节:对于多字节字符,按规则组合相应的字节以形成完整的字符。
4、转换为字符:将组合后的字节序列转换为对应的 Unicode 码点,再转换为字符。
说明下,识别为单字节还是多字节字符的具体规则如:
1、单字节字符
- 如果字节的第一位是0(即(b & 0x80) == 0),则该字节是一个单字节字符。
- 直接取8位二进制数转换成Unicode字符。
2、双字节字符 - 如果字节的前三位是110(即(b & 0xE0) == 0xC0),则该字节是一个双字节字符的开始。
- 组合当前字节和下一个字节,并将其转换为字符。即:取16位二进制数转换为Unicode字符。
3、三字节字符 - 如果字节的前四位是1110(即(b & 0xF0) == 0xE0),则该字节是一个三字节字符的开始。
- 组合当前字节及其后两个字节,并将其转换为字符。即:取24位二进制数转换为Unicode字符。
4、四字节字符 - 如果字节的前五位是11110(即(b & 0xF8) == 0xF0),则该字节是一个四字节字符的开始。
- 组合当前字节及其后三个字节,并将其转换为字符。即:取32位二进制数转换为Unicode字符。
解析原理代码示例:
import java.nio.charset.StandardCharsets;
public class Utf8DecodeExample {
public static void main(String[] args) {
byte[] byteArray = { (byte) 0xE4, (byte) 0xBD, (byte) 0xA0, (byte) 0xE5, (byte) 0xA5, (byte) 0xBD, (byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x8A };
StringBuilder decodedString = new StringBuilder();
int i = 0;
while (i < byteArray.length) {
byte b = byteArray[i];
if ((b & 0x80) == 0) {
// 单字节字符 (0xxxxxxx)
decodedString.append((char) b);
i++;
} else if ((b & 0xE0) == 0xC0) {
// 双字节字符 (110xxxxx 10xxxxxx)
int codePoint = ((b & 0x1F) << 6) | (byteArray[i + 1] & 0x3F);
decodedString.append((char) codePoint);
i += 2;
} else if ((b & 0xF0) == 0xE0) {
// 三字节字符 (1110xxxx 10xxxxxx 10xxxxxx)
int codePoint = ((b & 0x0F) << 12) | ((byteArray[i + 1] & 0x3F) << 6) | (byteArray[i + 2] & 0x3F);
decodedString.append((char) codePoint);
i += 3;
} else if ((b & 0xF8) == 0xF0) {
// 四字节字符 (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
int codePoint = ((b & 0x07) << 18) | ((byteArray[i + 1] & 0x3F) << 12) | ((byteArray[i + 2] & 0x3F) << 6) | (byteArray[i + 3] & 0x3F);
decodedString.append(Character.toChars(codePoint));
i += 4;
}
}
System.out.println("Decoded string: " + decodedString.toString());
}
}
可以直接使用现成的方法new String()。
代码示例:
import java.nio.charset.StandardCharsets;
public class BinaryToStringExample {
public static void main(String[] args) {
// 已编码的字节数组(假设这是从某个地方获取的二进制数据)
byte[] encodedBytes = {72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33};
// 使用 UTF-8 解码将字节数组转换回字符串
String decodedString = new String(encodedBytes, StandardCharsets.UTF_8);
// 打印还原后的字符串
System.out.println("Decoded string: " + decodedString);
}
}
输出示例:
Decoded string: Hello, World!
解释:
第一步编码我们打印%02X指定输出为十六进制数据,实际上十六进制的48就是十进制的72。
(3)、编码与解码的原理
1、字符编码
字符编码是将字符集中的字符映射到一组数字(通常是整数),然后进一步映射到二进制表示的过程。
编码过程:先将字符转字节数组,在将字节数组转二进制的过程。
常见的字符编码标准有:
- ASCII:仅支持128个字符,每个字符用7位表示(实际使用8位)。
- UTF-8:一种变长编码,兼容ASCII,单字节字符用1字节表示,其他字符可能需要2到4字节。
- UTF-16:另一种变长编码,基本多文种平面(BMP)中的字符用2字节表示,其他字符用4字节表示。
2、Java中的字符编码
在Java中,字符串是以Unicode格式存储的,具体来说是使用UTF-16编码。当你使用getBytes()方法时,你可以指定一个字符集(如UTF-8或UTF-16),该方法会根据指定的字符集将字符串转换为字节数组。
getBytes(Charset charset)方法:
- 参数:指定要使用的字符集(如StandardCharsets.UTF_8)。
- 返回值:返回一个字节数组,表示编码后的二进制数据。
new String(byte[] bytes, Charset charset)方法:
- 参数:
- bytes:包含二进制数据的字节数组。
- charset:指定要使用的字符集(如StandardCharsets.UTF_8)。
- 返回值:返回一个字符串,表示解码后的文本。
示例:处理非ASCII字符
import java.nio.charset.StandardCharsets;
public class NonAsciiEncodingExample {
public static void main(String[] args) {
// 包含非ASCII字符的字符串
String originalString = "你好,世界!";
// 使用UTF-8编码将字符串转换为字节数组(二进制)
byte[] encodedBytes = originalString.getBytes(StandardCharsets.UTF_8);
// 打印字节数组
System.out.println("Encoded bytes (in hex):");
for (byte b : encodedBytes) {
System.out.printf("%02X ", b); // 十六进制(4位)展示每个字节
}
System.out.println();
// 可选:打印每个字节的二进制表示
System.out.println("Encoded bytes (in binary):");
for (byte b : encodedBytes) {
System.out.printf("%8s ", Integer.toBinaryString(b & 0xFF)); // 二进制展示
}
System.out.println();
}
}
输出示例:
Encoded bytes (in hex):
E4 BD A0 E5 A5 BD EF BC 8C E4 B8 96 E7 95 8C EF BC 81
Encoded bytes (in binary):
11100100 10111101 10100000 11100101 10100101 10111101 11101111 10111100 10101100 11100100 10111000 10010110 11100111 10010101 10001100 11101111 10111100 10100001
示例:解码非ASCII字符:
import java.nio.charset.StandardCharsets;
public class NonAsciiDecodingExample {
public static void main(String[] args) {
// 已编码的字节数组(假设这是从某个地方获取的二进制数据)
byte[] encodedBytes = { // 0x标识16进制的数
(byte) 0xE4, (byte) 0xBD, (byte) 0xA0,
(byte) 0xE5, (byte) 0xA5, (byte) 0xBD,
(byte) 0xEF, (byte) 0xBC, (byte) 0x8C,
(byte) 0xE4, (byte) 0xB8, (byte) 0x96,
(byte) 0xE7, (byte) 0x95, (byte) 0x8C,
(byte) 0xEF, (byte) 0xBC, (byte) 0x81
};
// 使用 UTF-8 解码将字节数组转换回字符串
String decodedString = new String(encodedBytes, StandardCharsets.UTF_8);
// 打印还原后的字符串
System.out.println("Decoded string: " + decodedString);
}
}
输出示例:
Decoded string: 你好,世界!
(4)、字符串和二进制转换总结
- 编码:将字符串转换为二进制数据的过程,涉及选择合适的字符编码标准(如UTF-8)。Java提供了getBytes(Charset charset)方法来进行编码操作。
- 解码:将二进制数据转换回字符串的过程,同样需要知道原始字符串使用的字符编码标准。Java提供了new String(byte[] bytes, Charset charset)方法来进行解码操作。
通过理解字符编码的基本原理和使用Java的内置方法,可以轻松地在字符串和二进制数据之间进行转换。这对于处理网络通信、文件存储等场景非常有用。
乘风破浪!Dare to Be!!!