本文主要介绍java字符的编码方式,包括unicode编码、码点、char类型、string类型等

1、char与unicode的关系与区别

unicode编码方式的出现原因正如其名,是为了统一各种字符编码的标准。在设计之初由于未能考虑到中文、日文等表意文字,所以仅仅才用了2个字节,也就是16位的编码方式,最多能容纳65536个字符,这种2字节标准的unicode编码称作UCS-2。与此同时java中char类型也采用了2个字节数的设计方法。因为char可以刚好表示UCS-2的所有字符。但是很快UCS-2就不够用了,之后又出现了UCS-4,即采用4个字节的的编码方式,此时char就不够用了。

2、char类型在java中表示

在讨论java如何解决USC-4所带来的char长度不够用带来的问题之前,我们先讨论java中char类型的表示方式。

//1. 符号表示
 		char a = 'A';
 		//2. 十六进制表示,\u转义序列表示转为字符
        char b = '\u2122';
        //或
        String c = "\u2122";

16进制的表示方式刚好表示:\u0000-\uffff(从0000到ffff个字符),USC-2中所有字符。

3、char类型如何表示UCS-4

首先说明两个概念:
码点:一个编码表中的某个字符对应的代码值。例如:\u2122就是一个码点
代码单元:一个char类型表示的编码范围。
例如:"\uD835\uDD46"是一个又两个代码单元构成的码点。

为了表示USC-4表示的字符,java采取的方式很简单,采用两个代码单元表示一个USC-4字符
对于UCS-2中的字符,使用一个代码单元就够了。

String b = "\uD835\uDD46";
        System.out.println(b);

上述输出为:

java中char采用什么编码 在java中,char采用什么编码方案_System

4、java代码中如何操作码点

参考下述代码,输出正确吗?

String b = "\uD835\uDD46\u0001";
        for (int j = 0; j < b.length(); j++) {
            System.out.println(b.charAt(j));
        }

输出:

java中char采用什么编码 在java中,char采用什么编码方案_java_02


这个输出明显是不正确的,因为String b = "\uD835\uDD46\u0001";是由两个字符组成的,第一个字符是一个UCS-4的字符,由两个代码单元构成。

因此可以看到,string.length()获取的是代码单元的数量,是按代码单元遍历的,一旦出现双代码单元的字符就会出问题。

那么如何按码点遍历呢?
1.码点的基本操作

//1.获取码点的数量
        String str = "test\uD835\uDD46";//5个码点
        int cpCount = str.codePointCount(0, str.length());
        System.out.println(cpCount);//输出5
//2.获取第i(i=5)个码点,打印码点和字符
        int cp5 = str.offsetByCodePoints(0, 4);
        int cpi = str.codePointAt(cp5);
        System.out.println(cpi+"-->"+(char) cpi);
        System.out.println();
//3.获取字符串的码点数组
        int[] cpArray = str.codePoints().toArray();
//4.将码点数组转换成字符串
        String s = new String(cpArray, 0, cpArray.length);
        System.out.println(s);
//5.判断是否时由双代码单元构成的字符,是返回true,否则返回false
		Character.isSupplementaryCodePoint(int cp)

2.遍历字符串

//获取字符串的码点数组,并根据码点遍历数组
		String str = "test\uD835\uDD46";//5个码点的字符串
        int[] cpArray = str.codePoints().toArray();
        for (int cpA : cpArray) {
            System.out.print(cpA+"-->"+(char)cpA+"\t");
        }
        System.out.println();

        //根据字符单元遍历字符串
        for (int j = 0; j < str.length();) {
            //获取第j个码点
            int iCP = str.codePointAt(j);
            if(Character.isSupplementaryCodePoint(cpArray[j])){
                j+=2;
            }else {
                ++j;
            }
            System.out.println((char)iCP+"\t");
        }