字符集编码
OriginalAbout 4 min
在所经历的开发生涯中,碰到很多问题都是跟编码相关的。其中乱码的问题在Jsp
盛行的时代最常见不过了,今天我们就来看看Java的日常使用中,怎样能够用好这个字符集编码。
Java中的编码
有三个比较重要的概念:encoding
, charsets
, and code point
Encoding
计算机只能理解1
和0
这种二进制表示形式。处理其他任何内容都需要某种从现实世界文本到其二进制表示形式的映射。这种映射就是我们所说的字符编码或简称为编码。
比如说:我
在UTF-8
编码成``
Latin
这个又是啥GBK
ISO-8859-1
ASCII
Charset
UTF-8
是一种可变长度字符编码方式,用于表示Unicode
中的字符。它的编码规则如下:
- 字符范围:
UTF-8
可以表示Unicode
中的所有字符,包括基本多文种平面(BMP)和辅助平面(SupplementaryPlanes)中的字符。 - 编码方式:
- 单字节字符
(U+0000~U+007F)
:对于英文、数字、标点符号等基本ASCII字符,采用单字节编码,最高位为0,后面跟着7位字符的Unicode代码点。 - 多字节字符:对于非ASCII字符,采用多字节编码。UTF-8采用可变长度编码方式,根据字符的Unicode代码点范围,使用2到4个字节来表示。
- 单字节字符
- 多字节编码:
- 对于2字节编码(U+0080到U+07FF范围内的字符):以110xxxxx10xxxxxx的格式编码,其中高5位为110,低6位为Unicode代码点的高5位,中间6位为Unicode代码点的低6位。
- 对于3字节编码(U+0800到U+FFFF范围内的字符):以1110xxxx10xxxxxx10xxxxxx的格式编码,其中高4位为1110,中间6位为Unicode代码点的高4位,最后6位为Unicode代码点的低6位。
- 对于4字节编码(U+10000到U+10FFFF范围内的字符):以11110xxx10xxxxxx10xxxxxx10xxxxxx的格式编码,其中高3位为11110,接下来的每个字节的高2位都为10,最后6位为Unicode代码点的低6位。
- 字节序:
UTF-8
没有字节序问题,字节的顺序与代码点的顺序一致。
Question
: 为什么字符是通过字节来存储而不是位
Answer
: 主要有以下几个原因
- 内存对齐: 以字节为单位存储字符可以更好地与内存对齐的要求相匹配
- 处理器架构: 处理器通常在字节级别上操作数据。即使某些处理器支持位级操作,但在实际编程中,通常更容易使用字节级操作。这使得以字节为单位存储字符更为方便和高效。
Codepoints
关于utf-8的codePoints: https://www.charset.org/utf-8
编码会牵扯到很多其他的概念,
- 系统的编码
- JVM的编码
- 源文件的编码
Tips
UTF-8编码下的
- 数字和英文字母占据一个字节
- 通常汉字占三个字节,扩展B区以后的汉字占四个字节
var list = List.of("我", "1", "i", "😜");
list.forEach(string -> System.out.println(string.getBytes(StandardCharsets.UTF_8).length)); // 3 1 1 4
byte
vs char
乱码
- 编码与解码的不一致
Question
: 为什么要对URL进行编码?
Answer
: 对URL
进行编码操作是为了确保URL
中包含的特殊字符能够被正确地传输和解析,同时确保URL
的格式合法性和完整性。
- 特殊字符处理:URL 中有一些特殊字符,如空格、问号、等号、斜杠等,这些字符在 URL 中具有特殊含义或者可能与 URL 结构发生冲突。通过编码这些特殊字符,可以确保它们不会被误解为 URL 结构的一部分,而被正确地传输和解析。
- URL 格式合法性:URL 中只能包含特定的字符集,包括字母、数字、一些特殊字符(如 -、.、_、~)等。如果 URL 中包含其他字符,就需要对其进行编码,以确保 URL 的格式合法性。
- 传输安全性:在 URL 中直接包含敏感信息(如密码、特殊字符等)可能会导致安全问题,例如泄露敏感信息、URL 注入攻击等。通过编码这些信息,可以提高 URL 的安全性,减少安全风险
数据库中的编码
Web的编码
最佳实践
Java中不要使用默认的字符集编码
默认字符集编码取决于操作系统和JVM
的设置,因此在不同的环境下可能会有不同的结果。这可能导致在不同平台上运行的程序之间出现字符集不一致的问题,从而导致意外的行为或错误。所以JAVA
的标准库中,有关编码和解码的方法,都建议指定字符集。
// 在URLDecoder中的两个方法,不带Charset参数的方法已被废弃
@Deprecated
public static String decode(String s) {
....
}
public static String decode(String s, Charset charset) {
...
}