面试题一:Java的char是两个字节,如何存UTF-8字符?

Java的char是两个字节,如何存UTF-8字符?

一、面试官视角:这道题想考察什么?

  • 是否熟悉Java char和字符串(初级)
  • 是否了解字符的映射和存储细节(中级)
  • 是否能触类旁通,横向对比其他语言(高级)

二、题目剖析:

1、分别占多少字节?

char(字符数据类型)可以存储两个字节(byte),UTF-8可以存储一到三个字节

2、和Unicode什么关系?

1
2
3
4
5
6
7
8
char u8Test = "庆";

Integer.toHexString(u8Test);

// 打印出来是:0x5e 0x86两个字节,这两个字节就是Unicode码点,所以Unicode其实就是字符集
// ASCII码也是字符集,ASCII码与Unicode两者是兼容关系
// 字符集的作用是:完成字符到整数的映射
// 字符集不是编码,UTF-8是编码

3、如何存储字符?

一个字符(如笑脸)是两个字节(0xd83d,0xde00),这两个字节其实就是字符集(Unicode、ASCII码)码点,如果通过UTF-8编码,会转换成byte类型,也就是四个字节(11110000,10011111,10011000,10000000),但在Java char里面,会通过UTF-16进行编码,转换成byte类型对应的四个字节(11011000(d8),00111101(3d),11011110(de),00000000(00)),然后通过计算器存储(比如序列化或磁盘),其实无所谓存不存的,因为在Java char里面,存储的是UTF-16编码后的字节,跟UTF-8没有关系。

Tip:UTF-8与UTF-16的区别是:UTF-8最小的单位是一个字节,UTF-16最小的单位是两个字节。

(如果字符是一个A,它对应的是65,用ASCII码7个bit来表示,但在UTF-16里面也是需要两个字节的)

4、字符串长度

1
2
3
4
5
6
7
8
9
10
11
java:
String emoji = “笑脸”;
System.out.println(emoji.length()); // 长度为:2

// jdk9对Latin字符的存储空间做了优化,但字符串长度不等于字符数

python:
emoji = u"笑脸"
print(len(emoji)) // 长度为:1

// 这一点python就做的很好

三、题目结论:

  • Java char 不存UTF-8的字节,而是UTF-16
  • Unicode通用字符占两个字节,例如“中”
  • Unicode扩展字符集需要用一对char来表示,例如“笑脸”
  • Unicode是字符集,不是编码,作用类似于ASCII码
  • Java String的length不是字符数,而是char的个数

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!