源码解读-String(一)

1.String类型是不可变的,除了StringBuffer可以改变String之外。
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared.
2.public final class String implements java.io.Serializable, Comparable<String>, CharSequence

String类实现了java.io.Serializable接口,Comparable接口以及CharSequence的接口,接下来分别简述一下这些接口:

java.io.Serializable:该接口没有具体方法需要实现,只是标记了该类是可以被序列化的类。具体序列化的知识会再写一篇序列化的总结,目前可以先参考https://www.cnblogs.com/wangg-mail/p/4354709.html中的对序列化的讲解,其中比较重要的有transient关键字以及serialVersionUID属性,以及知识点,如果父类没有标记可序列化,子类标记序列化,那么父类的属性就不能被序列化。

Comparable:实现类的自然排序,实现compareTo方法。

CharSequence:包括了length(), charAt(int index), subSequence(int start, int end)等方法。

3.private final char value[];

String类型的第一个属性,用于存储字符数据。

4.private int hash; 

String类型的第二个属性,用于缓存String字符串的hash值,默认为0。

5.private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

String类型的第三个属性,一个有关于流的对象数组(不理解是做啥的)

6.public String() {
    this.value = new char[0];
}

构造方法,为空的时候构造一个长度为0的char数组,但是注释中说,因为Stirng的不可变性,这个构造器变得没有用处。

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

构造方法,传入一个String将其属性赋值给new出来的新的String,注释中表示,除非非常有必要的赋值,不然这样的构造也是不需要的。

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

构造方法,表示将一个char数组赋值给String,注释中说明,char[]如果有后续的改变是不会改变String的。

9.public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // 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);
}

构造方法,截取字符数组的片段来生成String

10.public String(int[] codePoints, int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // 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;
    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;
}

构造方法,通过整型数组来构造String,原理是Unicode,其中在构造时会判断char的具体大小,因为,int型所代表的大小可能会超过char的大小(2字节)所以,需要精确计算变成char[]的大小,如果是isBmpCodePoint,说明是两个字节之内,可以直接强转成char,如果超过2字节,那么会用两个char来接这个unicode(涉及Unicode知识,待后续补充)

接下来省略一些构造方法。。。

11.public String(StringBuffer buffer) {
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}

构造方法,用StringBuffer来构造,会发现这里对入参buffer加了synchronized锁,意思是当线程获得buffer对象的monitor的时候,如果访问了String类的该锁块的构造方法,那么buffer对象会被加上锁,其他的线程就不能访问这个buffer。

12.public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

构造方法,用StringBuilder来构造。

13.public int length() {
    return value.length;
}

返回字符串长度,其实可以发现其实字符串长度返回的就是char[]的长度。

14.public boolean isEmpty() {
    return value.length == 0;
}

检查是否为空,判断的方式是length==0。

15.public char charAt(int index) {
    if ((index < 0) || (index >= value.length)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return value[index];
}

返回规定下标的char。

16.public byte[] getBytes(Charset charset) {
    if (charset == null) throw new NullPointerException();
    return StringCoding.encode(charset, value, 0, value.length);
}

常用的方法转化字符串的字符集编码(具体如何实现的待分析),返回byte数组,一般会讲这个byte数组new一个新的String,就可以将String的字符集编码转化。

17.public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String重写了Object的equals方法,首先直接先判断他们的内存地址是否一样,如果一样直接返回true,然后判断入参是否是String类型不是的话直接返回false,再判断value[]的长度,如果相等的话,才继续判断他们其中的值。

18.public boolean contentEquals(StringBuffer sb) {
    return contentEquals((CharSequence)sb);
}
19.private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
    char v1[] = value;
    char v2[] = sb.getValue();
    int n = v1.length;
    if (n != sb.length()) {
        return false;
    }
    for (int i = 0; i < n; i++) {
        if (v1[i] != v2[i]) {
            return false;
        }
    }
    return true;
}
20.public boolean contentEquals(CharSequence cs) {
    // Argument is a StringBuffer, StringBuilder
    if (cs instanceof AbstractStringBuilder) {
        if (cs instanceof StringBuffer) {
            synchronized(cs) {
               return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        } else {
            return nonSyncContentEquals((AbstractStringBuilder)cs);
        }
    }
    // Argument is a String
    if (cs.equals(this))
        return true;
    // Argument is a generic CharSequence
    char v1[] = value;
    int n = v1.length;
    if (n != cs.length()) {
        return false;
    }
    for (int i = 0; i < n; i++) {
        if (v1[i] != cs.charAt(i)) {
            return false;
        }
    }
    return true;
}

判断StringBuffer与String是否相等,值得注意的是StringBuffer是可以强转的charSqeuence的,通过【19】的代码我们可以知道,StringBuffer和StringBuilder都继承了AbstractStringBuilder,在这个【20】contentEquals的方法上,只是StringBuffer被加了锁。

21.public boolean equalsIgnoreCase(String anotherString) {
    return (this == anotherString) ? true
            : (anotherString != null)
            && (anotherString.value.length == value.length)
            && regionMatches(true, 0, anotherString, 0, value.length);
}

忽略大小写判断两个字符串是否相等其中,regionMatches是判断字符串在某个区间是否相等,第一个true表示忽略大小写。

22.public boolean regionMatches(boolean ignoreCase, int toffset,
        String other, int ooffset, int len) {
    char ta[] = value;
    int to = toffset;
    char pa[] = other.value;
    int po = ooffset;
    // Note: toffset, ooffset, or len might be near -1>>>1.
    if ((ooffset < 0) || (toffset < 0)
            || (toffset > (long)value.length - len)
            || (ooffset > (long)other.value.length - len)) {
        return false;
    }
    while (len-- > 0) {
        char c1 = ta[to++];
        char c2 = pa[po++];
        if (c1 == c2) {
            continue;
        }
        if (ignoreCase) {
            // If characters don't match but case may be ignored,
            // try converting both characters to uppercase.
            // If the results match, then the comparison scan should
            // continue.
            char u1 = Character.toUpperCase(c1);
            char u2 = Character.toUpperCase(c2);
            if (u1 == u2) {
                continue;
            }
            // Unfortunately, conversion to uppercase does not work properly
            // for the Georgian alphabet, which has strange rules about case
            // conversion.  So we need to make one last check before
            // exiting.
            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                continue;
            }
        }
        return false;
    }
    return true;
}

除了会检查toUpperCase以外,还会检查toLowerCase

猜你喜欢

转载自blog.csdn.net/weixin_38660814/article/details/81109665