Java 基础 -- 基础字符 char

char 在 Java 中是个很底层的东西了,比如 String 、StringBuilder 的底层就是它,但是在我们平时的工作中呢,很少使用他,不过既然是底层,今天我们大家就来一起研究下这 “哥们”。


char 用来表示 ==1 个字符== 。也就是说,如果你写 2个字符,那么这里是会报错的。如下:

// 这种编译报错 Too many characters in character literal
char c = '中国';

当然 char 也可以用来表示中文字符。在赋值时,我们经常这样表示:

 char c = '中';
        
 char c1 = 'H';

但是这里就会遇到一些面试上的坑了,比如使用字符类型进行算术运算和比较运算? 这是个什么鬼 A + B == ???

其实在 Java 内部进行字符处理时,采用的是 Unicode,(这里插一句 对 Unicode 和 UTF-X 的理解,Unicode 是一个包含世界各国字母的字符列表的编码。 Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode “,就是每一个字母对应一个编码 ID,是一种映射关系,我们可以理解为 Unicode 是 一个标准,一个规则,而 UTF-X 则是一种具体的对 Unicode 的实现,UTF-X 是一种 针对 Unicode 的可变长度字符编码,也是一种前缀码,是一种编码格式。它可以用来表 示Unicode标准中的任何字符,而且 UTF-8 是兼容 ASCII 的。UTF-8 是 Unicode 的 实现方式之一。)

char 本质上是一个固定占用 2 个字节的无符号正整数,对应 Unicode, 也就是说 上面 的 李, H 都分别对应一个 正整数,char 只能表示 Unicode 编号在 65 536 以内的字符。因为一个字节 只能表示 256 个符号,2 个字节就是 256 x 256 = 65536 个符号。那么如果超出范围该咋表示呢,用 2 个char!!!


既然了解完了 Unicode,那么每个字符都可以用一个 对应的 编码ID 表示,也就是 一个正整数。既然是数字了,自然可以进行算术运算和比较运算。

char 的 二进制转换

下面我们就以 Integer 的转换二进制函数 toBinaryString 为例,说明一下 char 字节在 Java 中如何转换二进制的。

    public static void main(String[] args) {
        char c = '中';
        System.out.println(Integer.toBinaryString(c));
       // 二进制为:  100111000101101
    }

我们给 char 赋值一个 中文 字节 中,然后求出它的 二进制。

Integer 的 toBinaryString 方法:

    /**
     *   返回 输入参数 i 的 二进制字符串
     */
    public static String toBinaryString(int i) {
        return toUnsignedString0(i, 1);
    }

这里调用了 toUnsignedString0, 如下

   /**
     * Convert the integer to an unsigned number.
     * 转换一个 整型到一个无符号二进制数字
     */
    private static String toUnsignedString0(int val, int shift) {
        // 这里断言忽略
        // assert shift > 0 && shift <=5 : "Illegal shift value";
        // Integer.numberOfLeadingZeros 返回无符号整型的最高非零位前面的0的个数,包括符号位在内
        // 比如 Integer.numberOfLeadingZeros(10) 结果是 28
        // Integer.SIZE 为 32
        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
        char[] buf = new char[chars];

        // 这里是整个方法的核心,整数转换二进制,然后更新 char 的缓冲
        formatUnsignedInt(val, shift, buf, 0, chars);

        // Use special constructor which takes over "buf".
        return new String(buf, true);
    }

核心转换函数 formatUnsignedInt 如下:

   /**
     * 格式化到字符缓冲区
     * @param val 被格式化的数
     * @param shift 格式化的类型 (4 代表16进制, 3 代表8进制, 1 代表二进制)
     * @param buf 待写入的字符缓冲区
     * @param offset 字符开始的位置
     * @param len 要写的字符数
     * @return the lowest character  location used
     */
   static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
        int charPos = len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            // 二进制的 & 运算,求出下标,然后获取 digits 中对应的值,写入 buf 缓冲区
            // final static char[] digits = {
            //               '0' , '1' , '2' , '3' , '4' , '5' ,
            //               '6' , '7' , '8' , '9' , 'a' , 'b' ,
            //               'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
            //               'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
            //               'o' , 'p' , 'q' , 'r' , 's' , 't' ,
            //               'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    }
            buf[offset + --charPos] = Integer.digits[val & mask];
            // 无符号右移
            val >>>= shift;
        } while (val != 0 && charPos > 0);
        return charPos;
    }

通过上面的代码可以看出,Integer 内部维护了一个 char 数组,我们的普通字符转换 二进制的时候,都是求出 digits 某个下标的值,然后写到缓冲区,以 String 的形式返回给用户的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券