A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

String类源码分析 -- by maxwell

今天把String类的源码看了一遍,该类大概2000多行代码,注释就有1000多行。这个类主要都是对char[]的操作。
我大概注释了60%左右的方法,重要的方法做了分析注释,对这些方法也算有了比较深刻的认识。

String的底层是使用数组实现的。
/** The value is used for character storage. */
    private final char value[];

构造方法
//无参构造
public String() {
        this.value = new char[0];
}
//将char[]转化为字符串
public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
}

//分配一个新的 String,它包含取自字符数组参数一个子数组的字符。
//offset 参数是子数组第一个字符的索引,count 参数指定子数组的长度。
//实际上是调用了Arrays.copyOfRange()方法实现的。
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);
}

//将byte[]转化为字符串
public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length); //检查边界,这个方法里面就是使用if()语句判断边界是否合法
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
}

//上面调用的checkBounds()方法,该方法是private的,用于检测边界值
private static void checkBounds(byte[] bytes, int offset, int length) {
        if (length < 0)
                throw new StringIndexOutOfBoundsException(length);
        if (offset < 0)
                throw new StringIndexOutOfBoundsException(offset);
        if (offset > bytes.length - length)
                throw new StringIndexOutOfBoundsException(offset + length);
}

//将StringBuffer类型数据转化为字符串
//底层实现是使用的Arrays.copyOf()方法
public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
}
//将StringBuilderr类型数据转化为字符串,实现和StringBuffer的是一样的
public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

常用方法
//获取字符串长度
//实际上就是返回了char[]的长度
public int length() {
        return value.length;
}

//判断字符串是否为空串
//实际上就是判断数组的长度是否为0
public boolean isEmpty() {
        return value.length == 0;
}

//取指定index位置上的char值
//实际上是通过index返回char[]数组的内容
public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
                throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
}

//从dstBegin开始位置到字符串结束的字符都拷贝到dst[]数组中
//注意这个方法的返回值是void,返回后的字符数组在dst[]中
//实际上是使用System.arraycopy()实现的数组拷贝。而System.arraycopy()底层是使用c++实现的
void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
}

//该方法是对上面方法的扩充,只是加上了边界检查
//实际上还是使用System.arraycopy()实现的
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
                throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
                throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
                throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

//已过时的方法,但是该代码还是可以学习的
//使用while遍历
@Deprecated
public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
        if (srcBegin < 0) {
                throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
                throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
                throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        int j = dstBegin; //开始位置
        int n = srcEnd; //结束位置
        int i = srcBegin; //索引初始为开始位置
        char[] val = value;   /* avoid getfield opcode */ //复制一份数组,避免直接操作成员变量

        while (i < n) {
                dst[j++] = (byte)val[i++]; //实现数组拷贝,强制为byte
        }
}

//判断当前字符串是否和传入的anObject相等
//这是一个非常重要的方法,重写了Object的equals方法,用来比较字符串内容是否相等。
public boolean equals(Object anObject) {
        if (this == anObject) { //如果传入的就是字符串对象本身
                return true;
        }
        if (anObject instanceof String) { //如果传入的是String对象的引用吗,只有两个对象类型相同才有可比性
                String anotherString = (String) anObject;
                int n = value.length; //n控制while()循环的次数,及当前字符串的长度
                if (n == anotherString.value.length) { //如果两字符串长度相等
                        char v1[] = value;
                        char v2[] = anotherString.value;
                        int i = 0; //初始索引为0
                        while (n-- != 0) {
                                if (v1[i] != v2[i]) //遍历两个字符数组,如果遇到了不相等的字符,直接返回false
                                                return false;
                                i++;
                        }
                        return true;
                }
        }
        return false;
}

//contentEquals()方法将此字符串与指定的 CharSequence 比较。
//实现方式和上面的equals()方法类似,但是CharSequence是接口。
//String, StringBuffer, StringBuilder等类都实现了CharSequence接口。
public boolean contentEquals(CharSequence cs) {
        if (value.length != cs.length())
                return false;
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) { //如果参数是StringBuffer或StringBuilder
                char v1[] = value;
                char v2[] = ((AbstractStringBuilder) cs).getValue();
                int i = 0;
                int n = value.length;
                while (n-- != 0) {
                        if (v1[i] != v2[i])
                                return false;
                        i++;
                }
                return true;
        }
        // Argument is a String
        if (cs.equals(this)) //如果参数是String
                return true;
        // Argument is a generic CharSequence
        // 如果参数是其他实现类的对象
        char v1[] = value;
        int i = 0;
        int n = value.length;
        while (n-- != 0) {
                if (v1[i] != cs.charAt(i))
                        return false;
                i++;
        }
        return true;
}

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马