JDK8中String的字符编码
JDK 8 中,String以char[]
形式存储,字符串始终在内存中使用UTF-16编码,每个字符占用两个字节。
即使该字符是ASCII字符或Latin-1字符,这种情况也不例外。因此,可以确认在JDK 8中,String对象始终在内存中使用UTF-16编码。
你可以在输入、输出、转换过程中,将其指定为特定字符编码,如UTF-8
。
String a = "A你🚗";
byte[] bytes = a.getBytes(UTF_8);
System.out.println(bytes.length); // 1+3+4=8
JDK9中String的字符编码
在JDK 9中开始以byte[]
形式存储,因为JDK引入了Compact Strings
机制,以优化内存使用。String类根据字符串的实际内容在以下两种编码之间选择:
- Latin-1(ISO-8859-1): 如果字符串中的所有字符都处在Latin-1范围内(U+0000到U+00FF),则使用单字节编码(Latin-1)。
- UTF-16: 如果字符串包含超出Latin-1范围的字符(即U+0100及以上字符),则使用双字节编码(UTF-16)。
如果Compact Strings
被disabled,字符串将一直以UTF-16字符编码存储在byte[]数组中。
可以通过JVM参数:-XX:-CompactStrings
来禁用”Compact Strings”机制。
总结 :在JDK 8中,String类在内存中仅使用UTF-16编码。在JDK 9及更高版本中,String类在内存中支持两种编码:Latin-1和UTF-16。
UTF-8和UTF-16的区别是什么
- UTF-8
- 可变长度编码: UTF-8使用1到4个字节来编码每个Unicode字符。
- 1字节: 适用于基本ASCII字符(U+0000至U+007F)。
- 2字节: 适用于拉丁字母及其他常见字符(U+0080至U+07FF)。
- 3字节: 适用于多语言字符,包括汉字(U+0800至U+FFFF)。
- 4字节: 适用于辅助平面字符(U+10000至U+10FFFF)。
- 可变长度编码: UTF-8使用1到4个字节来编码每个Unicode字符。
- UTF-16
- 可变长度编码: UTF-16使用2或4个字节来编码每个Unicode字符。
- 2字节: 用于基本多语言平面内的字符(U+0000至U+FFFF),即通常通过单个16位代码单元表示。
- 4字节: 用于BMP外的字符(U+10000至U+10FFFF),需要使用一对代理对(Surrogate Pair),每对代理对由两个16位代码单元组成。
- 可变长度编码: UTF-16使用2或4个字节来编码每个Unicode字符。
因为存储原理上的区别:
- UTF-8
- 对于纯ASCII文本更为高效,因为每个字符仅占1个字节。
- 对于混合文本(包括ASCII和非ASCII字符),存储效率可变,但一般来说比UTF-16稍低,特别是当文本中包含大量非拉丁字符时。
- UTF-16
- 对于大量非ASCII字符(如汉字、日文假名等)的文本,UTF-16通常更为高效,因为大多数字符只占用2个字节。
- 单纯ASCII文本的存储效率较低,每个字符占用2个字节。
纯中文
String originalString = "世";
// String originalString = "世界";
// String originalString = "世界你好";
// 将字符串转换为UTF-8编码的字节数组
byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
// 将字符串转换为UTF-16编码的字节数组
byte[] utf16Bytes = originalString.getBytes(StandardCharsets.UTF_16);
System.out.println("Original: " + originalString);
//3->6->12
System.out.println("UTF-8 bytes length: " + utf8Bytes.length);
System.out.println();
System.out.println("UTF-16 bytes length: " + utf16Bytes.length);
//4->6->10
System.out.println();
纯英文
String originalString = "A";
// String originalString = "AB";
// String originalString = "ABCD";
// 将字符串转换为UTF-8编码的字节数组
byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
// 将字符串转换为UTF-16编码的字节数组
byte[] utf16Bytes = originalString.getBytes(StandardCharsets.UTF_16);
System.out.println("Original: " + originalString);
//1->2->4
System.out.println("UTF-8 bytes length: " + utf8Bytes.length);
System.out.println();
//4->6->10
System.out.println("UTF-16 bytes length: " + utf16Bytes.length);
System.out.println();
纯表情
String originalString = "🚗";
// String originalString = "🚗😊";
// String originalString = "🚗😊😭🔥";
// 将字符串转换为UTF-8编码的字节数组
byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
// 将字符串转换为UTF-16编码的字节数组
byte[] utf16Bytes = originalString.getBytes(StandardCharsets.UTF_16);
System.out.println("Original: " + originalString);
//4->8->16
System.out.println("UTF-8 bytes length: " + utf8Bytes.length);
System.out.println();
//4->6->10
System.out.println("UTF-16 bytes length: " + utf16Bytes.length);
System.out.println();
总结
- JDK 8 中的 String 类:
- 字符串始终在内存中使用UTF-16编码,每个字符占用两个字节。
- JDK 9 及更高版本中的 String 类:
- 使用”Compact Strings”机制,字符串可以在Latin-1或UTF-16编码之间动态选择,以提高内存使用效率。