要回答标题中的两个问题,先看下面的内容。
Unicode是一种字符集规范,而且还在不断发展之中。我们常说的UTF-8,UTF-16编码是其不同的两种实现。请注意,字符集和编码不是一回事。Unicode规范好比就是定义了每个字符对应一个数字,至于如何把这个数字存放在计算机中,那是另一回事。Unicode收录的每个字符对应一个数字,称作码点(code point),通常用“U+”后面跟着一个十六进制数表示。
其实UTF-16比UTF-8更早出现,在UTF-16之前还存在UCS-2,该编码固定使用16位编码,后来发现16位根本不够使用,IEEE曾推荐过UCS-4,即固定使用4个字节编码,但因为太过浪费空间被Unicode拒绝采纳了。此时,UTF-16就出现了。Unicode将16位的字符集做了延申,并规定每216为一个**plane, 第一个plane**称作 Basic Multilingual Plane(简称 BMP), 这里面的字符使用两个字节。对于超出了第一个plane的其他字符,将被收录在其他层级的plane,并使用第一层的代理(surrogate)将其表示,占用四个字节。至于怎么表示以及怎么编码解码的,请移步维基百科,有详细的解释。
JVM内部使用的是UTF-16编码。不管代码文件中char使用的是什么编码,都将被JVM转化为UTF-16而且只用两个字节,也就是说Java中的char占用两个字节,只能表示Unicode中第一层(BMP)中的字符,对于其他字符会报错:Invalid Character Constant, 而String中是可以的。
所以标题中的答案就是,之所以是两个字节,是因为Java内部使用UTF-16编码,所以char为了表示BMP中的字符,所以占了两个字节。很明显,不能表示所有字符。