zoukankan      html  css  js  c++  java
  • Java源码阅读计划(1) String<II>

    String的构造函数

    String有很多构造函数,不同种类的有不同的作用,接下来我们一个个看下去

    • 1
    public String() {
            this.value = "".value;
    }
    

    初始化一个String对象,使其表示一个空字符串序列,由于字符串的不可变性,这个方法其实是不必要的。

    • 2
        public String(String original) {
            this.value = original.value;
            this.hash = original.hash;
        }
    

    简单易懂,除非需要显式复制,否则这个方法也是不必要,因为字符串的不可变性。

    • 3
        public String(char value[]) {
            this.value = Arrays.copyOf(value, value.length);
        }
    
    

    依然很简单,不过要注意字符数组的后续修改不会影响新创建的字符串。

    • 4
        public String(char value[], int offset, int count) {
            if (offset < 0) {
                throw new StringIndexOutOfBoundsException(offset);
            }
            if (count <= 0) {
                if (count < 0) {
                    throw new StringIndexOutOfBoundsException(count);
                }
                if (offset <= value.length) {
                    this.value = "".value;
                    return;
                }
            }
            // Note: offset or count might be near -1>>>1.
            if (offset > value.length - count) {
                throw new StringIndexOutOfBoundsException(offset + count);
            }
            this.value = Arrays.copyOfRange(value, offset, offset+count);
        }
    

    这个方法是从字符数组中截取一段作为value的值,这里面做了一些关于长度与角标的判断,另外,同样的,这里形参char[]的改变与其之前所创建的String对象已经没有关系了

    • 5
       public String(int[] codePoints, int offset, int count) {
            if (offset < 0) { //简单的校验
                throw new StringIndexOutOfBoundsException(offset);
            }
            if (count <= 0) {
                if (count < 0) {  //简单的校验
                    throw new StringIndexOutOfBoundsException(count);
                }
                if (offset <= codePoints.length) { //如果截取起点大于int数组长度,那么返回空字符串
                    this.value = "".value;
                    return;
                }
            }
            // Note: offset or count might be near -1>>>1.
            if (offset > codePoints.length - count) { //简单的判断
                throw new StringIndexOutOfBoundsException(offset + count);
            }
    
            final int end = offset + count; //获取终点位置
    
            // Pass 1: Compute precise size of char[]
            int n = count; //由于Unicode的编码特点,字符串的真实长度并不是int数组的长度,用n这个变量来记录字符串的真实长度,下面的for循环就是在计算真正的长度
            for (int i = offset; i < end; i++) {
                int c = codePoints[i];
                if (Character.isBmpCodePoint(c))//一个码元长度
                    continue;
                else if (Character.isValidCodePoint(c))//两个码元长度,需要增加字符串长度
                    n++;
                else throw new IllegalArgumentException(Integer.toString(c));
            }
    
            // Pass 2: Allocate and fill in char[]
            final char[] v = new char[n];
    
            for (int i = offset, j = 0; i < end; i++, j++) {
                int c = codePoints[i];
                if (Character.isBmpCodePoint(c))
                    v[j] = (char)c;
                else
                    Character.toSurrogates(c, v, j++);
            }
    
            this.value = v;
        }
    

    这个方法涉及到Unicode编码的知识:
    传入int作为参数,这个int是这个字对应的Unicode(16进制数)。每个最大65535 0xFFFF

    public static final int MIN_CODE_POINT = 0x000000;
    
    public static final int MAX_CODE_POINT = 0X10FFFF;
    

    UTF-16中的基本单位是两个字节的码元,基本的码元范围是(0x0000-0xFFFF), UTF-16的字符映射范围是(U+0000,U+10FFFF),
    当一个生僻字符需要使用0xFFFF以上的映射范围时,其需要使用两个码元(4Byte)进行表示. 其映射规则如下
    第一个码元(前导代理)范围:0xD800 - 0xDBFF
    第二个码元(后尾代理)范围:0xDC00 - 0xDFFF
    有:(0xDBFF-0xD800+1)*(0xDFFF-0xDC00+1) === (0x10FFFF-0xFFFF)双射
    所以(0xD800 - 0xDBFF)范围内的码元不能单独表示字符,其必须与后尾代理一起构成一个完整字符.
    参考文档:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

       public String(int[] codePoints, int offset, int count) {
            if (offset < 0) { //简单的校验
                throw new StringIndexOutOfBoundsException(offset);
            }
            if (count <= 0) {
                if (count < 0) {  //简单的校验
                    throw new StringIndexOutOfBoundsException(count);
                }
                if (offset <= codePoints.length) { //如果截取起点大于int数组长度,那么返回空字符串
                    this.value = "".value;
                    return;
                }
            }
            // Note: offset or count might be near -1>>>1.
            if (offset > codePoints.length - count) { //简单的判断
                throw new StringIndexOutOfBoundsException(offset + count);
            }
    
            final int end = offset + count; //获取终点位置
    
            // Pass 1: Compute precise size of char[]
            int n = count; //由于Unicode的编码特点,字符串的真实长度并不是int数组的长度,用n这个变量来记录字符串的真实长度,下面的for循环就是在计算真正的长度
            for (int i = offset; i < end; i++) {
                int c = codePoints[i];
                if (Character.isBmpCodePoint(c))//一个码元长度
                    continue;
                else if (Character.isValidCodePoint(c))//两个码元长度,需要增加字符串长度
                    n++;
                else throw new IllegalArgumentException(Integer.toString(c));
            }
    
            // Pass 2: Allocate and fill in char[]
            final char[] v = new char[n];
    
            for (int i = offset, j = 0; i < end; i++, j++) {
                int c = codePoints[i];
                if (Character.isBmpCodePoint(c))
                    v[j] = (char)c;
                else
                    Character.toSurrogates(c, v, j++);
            }
    
            this.value = v;
        }
    

    这个方法涉及到Unicode编码的知识:
    传入int作为参数,这个int是这个字对应的Unicode(16进制数)。每个最大65535 0xFFFF

    public static final int MIN_CODE_POINT = 0x000000;
    
    public static final int MAX_CODE_POINT = 0X10FFFF;
    

    UTF-16中的基本单位是两个字节的码元,基本的码元范围是(0x0000-0xFFFF), UTF-16的字符映射范围是(U+0000,U+10FFFF),
    当一个生僻字符需要使用0xFFFF以上的映射范围时,其需要使用两个码元(4Byte)进行表示. 其映射规则如下
    第一个码元(前导代理)范围:0xD800 - 0xDBFF
    第二个码元(后尾代理)范围:0xDC00 - 0xDFFF
    有:(0xDBFF-0xD800+1)*(0xDFFF-0xDC00+1) === (0x10FFFF-0xFFFF)双射
    所以(0xD800 - 0xDBFF)范围内的码元不能单独表示字符,其必须与后尾代理一起构成一个完整字符.
    参考文档:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

    • 6
        public String(StringBuilder builder) {
            this.value = Arrays.copyOf(builder.getValue(), builder.length());
        }
    
        public String(StringBuffer buffer) {
            synchronized(buffer) {
                this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
            }
        }
    

    这里也体现了StringBuilder和StringBuffer的并发安全性。

  • 相关阅读:
    MySQL安装图解
    程序员感触
    一个人的生活
    开始懂了
    limit 检索记录行
    Ajax的完整兼容各种浏览器版本代码
    java.lang.UnsupportedClassVersionError: Unsupported major.minor version 49.0的错误 [转]
    通信协议
    SDK
    毕业三个多月的感悟
  • 原文地址:https://www.cnblogs.com/figsprite/p/11795280.html
Copyright © 2011-2022 走看看