java String 源码阅读笔记以及Unicode的学习

来源:互联网 发布:单片机c语言教程 编辑:程序博客网 时间:2024/04/30 01:14

感悟

可以看到String中的方法,均是比较简短的方法,且每一行的长度都在idea
代码显示框的一半长左右。非常便于阅读。

源码分析

string的不可变性

  //从源码中可以看出string内部是通过数组实现的。其被final修饰,  //即一旦定义就不会再发生改变  private final char value[];

regionMatches 比较两个字符串区域是否相等

public boolean regionMatches(boolean ignoreCase, int toffset,        //......        while (len-- > 0) {            //......            if (ignoreCase) {                char u1 = Character.toUpperCase(c1);                char u2 = Character.toUpperCase(c2);                if (u1 == u2) {                    continue;                }                //注意这里,比较了大写后,依然要比较小写,对于格鲁吉亚                //字母,对大小写的规则比较特殊,要检查大小写全部检查才行                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {                    continue;                }            }            return false;        }        return true;    }

split方法

对于将 . \转义字符作为分隔符需要使用split(“\.”) split(“\|”),否则其默认
使用空字符分割的

limit 参数控制模式应用的次数,因此影响结果数组的长度。如果该限制 n 大
于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的
最后项将包含超出最后匹配的定界符的所有输入。如果 n 为非正,则模式将
被应用尽可能多的次数,而且数组可以是任意长度。如果 n 为零,则模式将
被应用尽可能多的次数,数组可有任何长度,并且结尾空字符串将被丢弃。

    public String[] split(String regex, int limit) {      //当regex的长度为1且不是“.$|()[{^?*+\\”中的时或者当长度为2时      //且第一个字符为“\”转义字符,第二个字符不是字符0-9 a-z A-Z 以及      //utf-16之间的字符时,通过indexof处理,否则采用正则表达式处理        char ch = 0;        if (((regex.value.length == 1 &&             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||             (regex.length() == 2 &&              regex.charAt(0) == '\\' &&              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&              ((ch-'a')|('z'-ch)) < 0 &&              ((ch-'A')|('Z'-ch)) < 0)) &&            (ch < Character.MIN_HIGH_SURROGATE ||             ch > Character.MAX_LOW_SURROGATE))        {            int off = 0;            int next = 0;            boolean limited = limit > 0;            ArrayList<String> list = new ArrayList<>();            while ((next = indexOf(ch, off)) != -1) {                if (!limited || list.size() < limit - 1) {                    list.add(substring(off, next));                    off = next + 1;                } else {    // last one                    //assert (list.size() == limit - 1);                    list.add(substring(off, value.length));                    off = value.length;                    break;                }            }            // If no match was found, return this            if (off == 0)                return new String[]{this};            // Add remaining segment            if (!limited || list.size() < limit)                list.add(substring(off, value.length));            // Construct result            int resultSize = list.size();            if (limit == 0)                while (resultSize > 0 && list.get(resultSize - 1).length() == 0)                    resultSize--;            String[] result = new String[resultSize];            return list.subList(0, resultSize).toArray(result);        }        return Pattern.compile(regex).split(this, limit);    }

indexof方法

查找一个字符的位置

   public int indexOf(int ch, int fromIndex) {        //如果是普通字符        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {            final char[] value = this.value;            for (int i = fromIndex; i < max; i++) {                if (value[i] == ch) {                    return i;                }            }            return -1;        } else {        //如果是汉字之类的字符            return indexOfSupplementary(ch, fromIndex);        }    }//根据i位置处的char,分别获得高位的btye值(放在char中)和低位的byte值和value数组比较    private int indexOfSupplementary(int ch, int fromIndex) {        if (Character.isValidCodePoint(ch)) {            final char[] value = this.value;            final char hi = Character.highSurrogate(ch);            final char lo = Character.lowSurrogate(ch);            final int max = value.length - 1;            for (int i = fromIndex; i < max; i++) {                if (value[i] == hi && value[i + 1] == lo) {                    return i;                }            }        }        return -1;    }

intern

一个和方法区相关的方法,在不同jdk版本中表现不一致(jdk6,jdk7),避免
使用吧。参考 http://blog.csdn.net/seu_calvin/article/details/52291082

string 相加的实现

  a = a + b;  //编译后会变成   (new StringBuilder()).append(a).append(b).toString();  //string是不可变的,这里生成了一个新的对象

关于java中的字符集

Unicode 只是字符集,而没有编码方式。其有一套标准,要求用1-4个字节来表示一个字符。
UTF-8 、UTF-16、UTF-32是 Unicode 字符集的编码方式

Unicode介绍

  1. Unicode的学名是”Universal Multiple-Octet Coded Character Set”,简
    称为UCS,UCS可以看作是”Unicode Character Set”的缩写
  2. 在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符
  3. 在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,UCS规范建议在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”,如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的.字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。
  4. 在 Java 中直接使用Unicode 转码时会按照UTF-16LE 的方式拆分,并加上 BOM。 如果采用 UTF-16 拆分,在 Java 中默认采用带有 BOM 的 UTF-16BE 拆分。
  5. 一个完整的Unicode字符叫代码点CodePoint,而一个Java char 叫代码单元code unit,占两个字节。
  6. string对象以UTF-16保存Unicode字符,需要用2个字符表示一个超大字符集。
  7. 汉字,这种表示方式为Sruuogate,第一个字符叫Surrogate High,第二个就是Surrogate Low。判断一个char是否是Surrogate区的字符,用Character的isHighSurrogate()/isLowSurrogate()方法。
  8. 我国本身的GB码(国标码)都没有把全部汉字收录,utf-16只是收录了常用的汉字。

bmp code

ISO 10646 定义了一个 31 位的字符集。然而,在这巨大的编码空间中,迄今为止只分配了前 65534 个码位 (0x0000 到 0xFFFD)。这个UCS的16位子集、称为基本多语言面 (Basic Multilingual Plane,BMP)。将被编码在16位BMP以外的字符都属于非常特殊的字符(比如象形文字),且只有专家在历史和科学领域里才会用到它们。按当前的计划,将来也许再也不会有字符被分配到从0x000000到0x10FFFF这个覆盖了超过100万个潜在的未来字符的 21 位的编码空间以外去了。

总结

Unicode和UTF-16:1个字符占2个字节(不管是哪国语言)

UTF-8:1个英文字符占1个字节,一个汉字(包括日文和韩文等)占3个字节

Java中的char默认采用Unicode编码,所以Java中char占2个字节

0 0