学习String源码的部分方法

先看构造器:


private final char value[];  //char类型的数组   以下均会用到
private int hash;  //缓存字符串的哈希值  //以下均会用到
public String() {
        this.value = "".value;  //声明时没有参数 则直接用空.value获取该value值,这个.value不太懂,个人认为应该是类似是将一个整体字符串,分割成char类型数组的方法。
    }
 public String(String original) {
        this.value = original.value;  //当存在值的时候 就将该值放到value中,也就是char类型的数组
        this.hash = original.hash;  //以及对应的哈希值
    }
public String(char value[]) {  //这个构造器说明了 String其实就是一个char类型的数组
        this.value = Arrays.copyOf(value, value.length);
    }
public String(char value[], int offset, int count) {  //给定起始下标和指定位数的构造器
        if (offset < 0) {  //先判断给定下标值是否符合逻辑,小于0则报字符串下标越界异常
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {  //再判断截取的位数是否符合逻辑,小于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);
    }

其他的构造参数也就类似以上四种,就不再一一列举。

然后就是比较常用的equals

public boolean equals(Object anObject) {
        if (this == anObject) {  //判断调用对象和传入对象的地址是不是一样的 如果一致则直接判断相同
            return true;
        }
        if (anObject instanceof String) {  //如果地址值不相同 则判断传入参数是否属于String类型
            String anotherString = (String)anObject;  //属于的话进行强转
            int n = value.length;
            if (n == anotherString.value.length) {  //判断转成字符串格式的传入参数长度是否跟要比较的字符串长度一样,不一样则直接返回false
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {  //长度一样的情况下,将两个字符串生成的字符数据挨个进行对比,用的其实还是==或者!=的方法,有一个不等于则返回false。
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;  //只有两个字符数字完全比较完,没有不相同的才会返回true;
            }
        }
        return false;
    }

截取字符串substring

public String substring(int beginIndex) {
        if (beginIndex < 0) {  //判断开始下标是否合理
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;  //比较字符串长度跟起始下标相减得到想要截取的长度 判断是否大于0,不大于则代表数组越界
                                //个人感觉直接判断起始下标跟总长度-1不就可以吗?可能是需要截取的长度本来就要用,所以直接拿截取长度跟0作比较了
if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); //如果截取起始下标为0,那就还返回整个字符串,如果不是则返回一个新字符串。 }

StringBuilder的部分源码,进行比较。还是先从构造器看起

public StringBuilder() {
        super(16);  //下面有super的解释
    }
AbstractStringBuilder(int capacity) {
        value = new char[capacity];  //由此可以看出 Stringbuilder也是一个字符数组 不过有给定初始长度 长度为6
    }

带有指定长度的构造器,跟第一个一样,不过初始长度改为指定值

public StringBuilder(int capacity) {
        super(capacity);  //初始长度改为参数值
    }

第三个,给定一个字符串为参数

public StringBuilder(String str) {
        super(str.length() + 16);  //给定字符串的长度加16作为初始长度。
        append(str); //并将其拼接 拼接的方法在AttributeStringBuilder中
    }
 public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();  //如果该字符为空 则返回appendNull()方法,以下有详解
        int len = str.length();
        ensureCapacityInternal(count + len);  //拿到一个足够容量大小的值
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);  //count是计算已经使用的字符个数的 同样也需要拿到一个足够大小的容量值
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }
private void ensureCapacityInternal(int minimumCapacity) {  //这个参数就是 上面的c+字符串的长度
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {  //如果已经使用的字符数加上字符串的长度大于整个字符数组的长度,那么就需要进行扩容了。
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));  //扩容时将之前的字符数组复制到一个新容量的字符数组中,从而保持原来的数据不会丢失
        }
    }
private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;  //先拿到原字符数组长度一半相加再加2
        if (newCapacity - minCapacity < 0) { //进行判断,看看扩容的值够不够大,没有给定的值大,那就用给定的值。
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)  //扩容之后的长度小于等于0或者扩容之后的长度大于数组最大值
            ? hugeCapacity(minCapacity)  //就需要看这个方法了
            : newCapacity;
    }
private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow  //超过最大值就内存溢出
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)  //大于数组最大值就用给定的值,如果小于数组最大值,那就用数组最大值。
            ? minCapacity : MAX_ARRAY_SIZE;
    } 
原文地址:https://www.cnblogs.com/qcq0703/p/12044474.html