写在前面

说说这几天看源码的感受吧,其实 jdk 中的源码设计是最值得进阶学习的地方。我们在对 api 较为熟悉之后,完全可以去尝试阅读一些 jdk 源码,打开 jdk 源码后,如果你英文能力稍微过得去,那么源码有相当详细的注释告诉你 api 的含义,具体用法。假设平时在写代码的过程中突然忘记了某个 api 的用法,那么有些新手没读过源码的可能顺手就打开百度或者谷歌,搜索 api 怎么用?哈哈哈,面向谷歌编程,这样的状态可能会让你一年的经验重复n年, 如果是阅读过源码,则直接进去看看源码英文注释,回想一下源码的实现即可使用,而且看过源码后,里面有些代码细节是可以在平时编码的过程中直接借鉴的。

废话有点多啦~~滴滴滴,上车了。。。

上一篇 String 源码浅析(一) 中已经对String前半部分源码做了解析,这篇把剩下的方法粗略的总结下…

String 成员方法

  • 判断字符串是否相等,该方法继承自Object类的重写实现,原则上也是比较字符串中的字符是否相等。

     1   public boolean equals(Object anObject) { 2    //判断形参跟当前字符串对象地址是否相等,即是否为同一个对象,如果相等,则返回true 3    if (this == anObject) { 4        return true; 5    } 6    //如果形参为String类型对象 7    if (anObject instanceof String) { 8        //强转为String类型对象 9        String anotherString = (String)anObject;10        //当前字符串对象的字符数组长度11        int n = value.length;12        //如果当前字符串对象的字符数组长度等于形参字符串字符数组长度13        if (n == anotherString.value.length) {14            //当前字符串字符数组15            char v1[] = value;16            //形参字符串字符数组17            char v2[] = anotherString.value;18            //遍历索引起始位置019            int i = 0;20            //遍历当前字符串字符数组,每个索引位置的字符与形参字符串索引位置字符比较,如果不相等则返回false21            while (n-- != 0) {22                if (v1[i] != v2[i])23                    return false;24                i++;25            }26            return true;27        }28    }29    //以上条件都不满足,最后返回false30    return false;31}
  • 传入CharSequence接口形参,实际是与StringBuffer,StringBuilder比较是否相等,因为StringBuffer,StringBuilder都实现了CharSequence接口

     1public boolean contentEquals(CharSequence cs) { 2    //判断形参是否是AbstractStringBuilder抽象类,实则因当传入的是其子类:StringBuffer, StringBuilder 3    if (cs instanceof AbstractStringBuilder) { 4        //如果形参是StringBuffer类型对象 5        if (cs instanceof StringBuffer) { 6            //同步锁,调用nonSyncContentEquals方法比较两种是否相等 7            synchronized(cs) { 8               return nonSyncContentEquals((AbstractStringBuilder)cs); 9            }10        } else {11            //如果形参对象是StringBuilder,则调用nonSyncContentEquals方法比较两种是否相等12            return nonSyncContentEquals((AbstractStringBuilder)cs);13        }14    }15    // 如果形参是String对象,则直接调用equals方法返回16    if (cs instanceof String) {17        return equals(cs);18    }19    // 如果是其他的CharSequence实现类,则遍历,一个个字符进行比较,找到一个字符不相等则直接返回false20    char v1[] = value;21    int n = v1.length;22    if (n != cs.length()) {23        return false;24    }25    for (int i = 0; i < n; i++) {26        if (v1[i] != cs.charAt(i)) {27            return false;28        }29    }30    //以上代码都不成立,走到最后直接返回true31    return true;32}
  • 私有方法,非同步方式(线程不安全)比较与 AbstractStringBuilder 是否相等,实则是与其子类:StringBuffer, StringBuilder 比较大小,contentEquals(CharSequence cs)方法中核心比较代码就是调用该方法。

     1  private boolean nonSyncContentEquals(AbstractStringBuilder sb) { 2    //当前字符串对象字符数组 3    char v1[] = value; 4    //获取形参字符数组 5    char v2[] = sb.getValue(); 6    //当前字符串对象字符数组长度 7    int n = v1.length; 8    //如果当前字符串对象字符数组长度不等于形参字符数组长度,则直接返回false 9    if (n != sb.length()) {10        return false;11    }12    //遍历当前字符串对象字符数组,与形参字符数组逐一比较字符,找到一个字符不相等,则直接返回false13    for (int i = 0; i < n; i++) {14        if (v1[i] != v2[i]) {15            return false;16        }17    }18    //以上条件都不成立,代码走到最后则直接返回true19    return true;20}
  • 公有方法,比较与StringBuffer对象是否相等,内部实则直接调用的contentEquals(CharSequence cs)方法,可以说该方法是StringBuffer的特别版吧。

    1  public boolean contentEquals(StringBuffer sb) {2    return contentEquals((CharSequence)sb);3}
  • 匹配两个字符串部分片段是否相等

     1  public boolean regionMatches(int toffset, String other, int ooffset, 2        int len) { 3    //当前字符串字符数组 4    char ta[] = value; 5    //当前字符串开始比较的起始位置,即偏移量 6    int to = toffset; 7    //待比较的字符串字符数组 8    char pa[] = other.value; 9    //待比较的字符串起始位置,即偏移量10    int po = ooffset;11    //索引检查 1.偏移量小于0  2. 偏移量大于总长度-待比较的长度12    //以上两种情况直接返回false13    if ((ooffset < 0) || (toffset < 0)14            || (toffset > (long)value.length - len)15            || (ooffset > (long)other.value.length - len)) {16        return false;17    }18    //遍历,找出不相等的字符,则返回false19    while (len-- > 0) {20        if (ta[to++] != pa[po++]) {21            return false;22        }23    }24    //不出意外,最终则返回true25    return true;26}
  • 匹配两个字符串部分片段是否相等,同时判断是否忽略大小写

     1public boolean regionMatches(boolean ignoreCase, int toffset, 2        String other, int ooffset, int len) { 3    //当前字符串字符数组 4    char ta[] = value; 5    //当前字符串开始比较的起始位置,即偏移量 6    int to = toffset; 7    //待比较的字符串字符数组 8    char pa[] = other.value; 9    //待比较的字符串起始位置,即偏移量10    int po = ooffset;11    //索引检查 1.偏移量小于0  2. 偏移量大于总长度-待比较的长度12    //以上两种情况直接返回false13    if ((ooffset < 0) || (toffset < 0)14            || (toffset > (long)value.length - len)15            || (ooffset > (long)other.value.length - len)) {16        return false;17    }18    //遍历检查字符是否相等,相等则跳过19    while (len-- > 0) {20        char c1 = ta[to++];21        char c2 = pa[po++];22        if (c1 == c2) {23            continue;24        }25        //如果字符不相等,且需要忽略大小写比较26        if (ignoreCase) {27            //字符转换为大写28            char u1 = Character.toUpperCase(c1);29            char u2 = Character.toUpperCase(c2);30            //如果相等,则继续跳过31            if (u1 == u2) {32                continue;33            }34            //转换为小写进行比较,如果相等则继续跳过35            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {36                continue;37            }38        }39        //否则发现不相等,则直接返回false40        return false;41    }42    //不出意外,最终返回true43    return true;44}
  • 忽略大小写比较字符串大小

     1 public boolean equalsIgnoreCase(String anotherString) { 2    //一句三目运算直接搞定 3    //如果当前字符串对象地址与形参字符串相等,则返回true 4    //否则判断形参字符串是否为空,形参字符串长度是否与当前字符串长度相等,直接调用regionMatches比较两个字符串所有字符是否相等,同时忽略大小写比较 5    //以上全部为true则相等 6    return (this == anotherString) ? true 7            : (anotherString != null) 8            && (anotherString.value.length == value.length) 9            && regionMatches(true, 0, anotherString, 0, value.length);10}
  • 比较两个字符串是否相等,该方法实现自Comparable接口,返回 int 结果,等于0,则字符串相等,小于0,则前者小于后者,大于0,则前者大于后者

     1  public int compareTo(String anotherString) { 2    //当前字符串字符数组长度 3    int len1 = value.length; 4    //待比较字符串字符数组长度 5    int len2 = anotherString.value.length; 6    //获取较小的长度 7    int lim = Math.min(len1, len2); 8    //当前字符串字符数组 9    char v1[] = value;10    //待比较的字符串字符数组11    char v2[] = anotherString.value;12    //索引位置0开始13    int k = 0;14    //遍历较小的字符数组15    while (k < lim) {16        char c1 = v1[k];17        char c2 = v2[k];18        //如果字符不相等19        if (c1 != c2) {20            //返回字符之差21            return c1 - c2;22        }23        k++;24    }25    //如果字符都相等,则返回长度之差26    return len1 - len2;27}
  • 使用默认比较器不区分大小写比较两个字符串大小

     1//初始化默认的比较器 2public static final Comparator<String> CASE_INSENSITIVE_ORDER 3                                     = new CaseInsensitiveComparator(); 4//默认的比较器,不区分大小写                           5private static class CaseInsensitiveComparator 6        implements Comparator<String>, java.io.Serializable { 7    // use serialVersionUID from JDK 1.2.2 for interoperability 8    private static final long serialVersionUID = 8575799808933029326L; 9    public int compare(String s1, String s2) {10        //第一个字符串长度11        int n1 = s1.length();12        //第二个字符串长度13        int n2 = s2.length();14        //取小15        int min = Math.min(n1, n2);16        //遍历较小的字符串17        for (int i = 0; i < min; i++) {18            //获取指定索引字符19            char c1 = s1.charAt(i);20            char c2 = s2.charAt(i);21            //如果字符不相等22            if (c1 != c2) {23                //转化为大写24                c1 = Character.toUpperCase(c1);25                c2 = Character.toUpperCase(c2);26                //转化为大写后比较,不相等27                if (c1 != c2) {28                    //转化为小写继续比较29                    c1 = Character.toLowerCase(c1);30                    c2 = Character.toLowerCase(c2);31                    //转化为小写字符,不相等32                    if (c1 != c2) {33                        //直接返回字符之差34                        return c1 - c2;35                    }36                }37            }38        }39        //不出意外,最终返回长度之差40        return n1 - n2;41    }42    /** Replaces the de-serialized object. */43    private Object readResolve() { return CASE_INSENSITIVE_ORDER; }44}4546//内部直接调用默认比较器的compare方法47public int compareToIgnoreCase(String str) {48    return CASE_INSENSITIVE_ORDER.compare(this, str);49}
  • 从指定偏移量开始,判断是否以指定字符串开头

     1 public boolean startsWith(String prefix, int toffset) { 2    //当前字符串字符数组 3    char ta[] = value; 4    //偏移量 5    int to = toffset; 6    //指定字符串前缀字符数组 7    char pa[] = prefix.value; 8    //索引位置0开始 9    int po = 0;10    //指定字符串前缀数组长度11    int pc = prefix.value.length;12    //偏移量小于0 或者 //偏移量大于总长度-字符串前缀长度,则直接返回false13    if ((toffset < 0) || (toffset > value.length - pc)) {14        return false;15    }16    //遍历前缀字符串17    while (--pc >= 0) {18        //从偏移量开始检索,找到字符不相等,则返回false19        if (ta[to++] != pa[po++]) {20            return false;21        }22    }23    //不出意外,最后则返回true24    return true;25}
  • 从字符串开头,判断是否以指定字符串开头

    1 public boolean startsWith(String prefix) {2    //直接调用startsWith重载方法,偏移量为03    return startsWith(prefix, 0);4}
  • 判断是否以指定字符串结尾,内部直接调用的 startsWith 方法,偏移量为总字符串长度-后缀字符串长度即可。

    1public boolean endsWith(String suffix) {2    return startsWith(suffix, value.length - suffix.value.length);3}
  • 从指定偏移量开始,搜索指定字符在字符串中第一次出现的索引位置

     1 public int indexOf(int ch, int fromIndex) { 2    //当前字符串字符数组长度 3    final int max = value.length; 4    //如果偏移量小于0,则重置为0 5    if (fromIndex < 0) { 6        fromIndex = 0; 7    } else if (fromIndex >= max) { 8        //偏移量大于总长度,则返回-1,意味着找不到指定字符 9        return -1;10    }11    if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {12        //当前字符串字符数组13        final char[] value = this.value;14        //从偏移量位置开始遍历15        for (int i = fromIndex; i < max; i++) {16            //找到相等的字符,则返回索引17            if (value[i] == ch) {18                return i;19            }20        }21        //找不到则返回-122        return -1;23    } else {24        return indexOfSupplementary(ch, fromIndex);25    }26}
  • 查找指定字符在字符串中第一次出现的索引位置,从偏移量0开始遍历查找

    1 public int indexOf(int ch) {2    return indexOf(ch, 0);3}
  • 查找指定字符在字符串中最后一次出现的索引位置,从指定偏移量开始遍历

     1  public int lastIndexOf(int ch, int fromIndex) { 2    if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 3        //当前字符串字符数组 4        final char[] value = this.value; 5        //偏移量与字符串最后的位置取小 6        int i = Math.min(fromIndex, value.length - 1); 7        //从后遍历字符数组 8        for (; i >= 0; i--) { 9            //找到相等的字符,返回索引10            if (value[i] == ch) {11                return i;12            }13        }14        //找不到则返回-115        return -1;16    } else {17        return lastIndexOfSupplementary(ch, fromIndex);18    }19}
  • 查找指定字符在字符串中最后一次出现的索引位置,从字符串最后一个索引位置开始遍历查找

    1 public int lastIndexOf(int ch) {2    return lastIndexOf(ch, value.length - 1);3}
  • 从指定位置开始,查找字符串在源字符串中第一次出现的的索引位置,内部实则直接调用的indexOf内部静态方法

    1  public int indexOf(String str, int fromIndex) {2    return indexOf(value, 0, value.length,3            str.value, 0, str.value.length, fromIndex);4}
  • 查找字符串在源字符串中第一次出现的的索引位置,内部实则直接调用的上述indexOf方法,fromIndex默认从0开始

    1 public int indexOf(String str) {2    return indexOf(str, 0);3}
  • 从指定位置开始,查找字符串在源字符串中最后一次出现的的索引位置,内部实则直接调用的lastIndexOf内部静态方法

    1 public int lastIndexOf(String str, int fromIndex) {2    return lastIndexOf(value, 0, value.length,3            str.value, 0, str.value.length, fromIndex);4}
  • 查找字符串在源字符串中最后一次出现的的索引位置,内部实则直接调用的上述lastIndexOf方法,fromIndex默认从value.length开始

    1public int lastIndexOf(String str) {2    return lastIndexOf(str, value.length);3}
  • 按照指定区间裁剪字符串,返回子字符串,beginIndex起始位置(包含),endIndex结束位置(不包含)

     1    public String substring(int beginIndex, int endIndex) { 2    //起始位置小于0,抛出索引越界异常 3    if (beginIndex < 0) { 4        throw new StringIndexOutOfBoundsException(beginIndex); 5    } 6    //结束位置大于字符串总长度,则抛出索引越界异常 7    if (endIndex > value.length) { 8        throw new StringIndexOutOfBoundsException(endIndex); 9    }10    //待截取的字符串长度11    int subLen = endIndex - beginIndex;12    //待截取的字符串长度小于0,则抛出索引越界异常13    if (subLen < 0) {14        throw new StringIndexOutOfBoundsException(subLen);15    }16    //三目判断 起始位置等于0,并且结束位置等于字符串长度,则表示为截取总长度,返回当前字符串对象17    //否则重新new一个字符串实例,从beginIndex开始,截取subLen长度18    return ((beginIndex == 0) && (endIndex == value.length)) ? this19            : new String(value, beginIndex, subLen);20}
  • 从起始位置beginIndex开始截取源字符串到结尾,返回子字符串

     1 public String substring(int beginIndex) { 2    //起始位置小于0,抛出索引越界异常 3    if (beginIndex < 0) { 4        throw new StringIndexOutOfBoundsException(beginIndex); 5    } 6    //待截取的字符串长度 7    int subLen = value.length - beginIndex; 8    //待截取的字符串长度小于0,则抛出索引越界异常 9    if (subLen < 0) {10        throw new StringIndexOutOfBoundsException(subLen);11    }12    //三目判断 起始位置等于0,则表示为截取总长度,返回当前字符串对象,否则重新new一个新的字符串实例,从beginIndex开始,截取subLen长度13    return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);14}
  • 按照指定区间裁剪字符串,返回CharSequence接口,beginIndex起始位置(包含),endIndex结束位置(不包含),内部实则直接调用的substring方法,只是返回的是最上层接口罢了

    1 public CharSequence subSequence(int beginIndex, int endIndex) {2    return this.substring(beginIndex, endIndex);3}
  • 字符串拼接,将目标字符串拼接在尾部,返回新的字符串

     1  public String concat(String str) { 2    //待拼接的字符串长度 3    int otherLen = str.length(); 4    //如果待拼接的字符串长度等于0,则直接返回当前字符串对象 5    if (otherLen == 0) { 6        return this; 7    } 8    //当前字符串长度 9    int len = value.length;10    //将当前字符串字符数组拷贝到新的字符数组buf[]中,长度扩容至len + otherLen11    char buf[] = Arrays.copyOf(value, len + otherLen);12    //将待拼接的字符数组拷贝至buf[]中,从len开始,理论上这部操作完之后,字符数组已经拼接成功了13    str.getChars(buf, len);14    //利用最新的字符数组,重新new一个新的字符串实例返回15    return new String(buf, true);16}
  • 将字符串中指定字符oldChar替换为新的字符newChar

     1  public String replace(char oldChar, char newChar) { 2    //如果旧的字符跟新的字符不相等,才执行替换逻辑,否则直接返回当前字符串对象 3    if (oldChar != newChar) { 4        //当前字符串长度 5        int len = value.length; 6        //索引从-1开始 7        int i = -1; 8        //当前字符串字符数组 9        char[] val = value;10        //遍历当前字符数组,从0开始,因为++i之后等于011        while (++i < len) {12            //找到与oldChar相等的字符,则中断循环13            if (val[i] == oldChar) {14                break;15            }16        }17        //如果oldChar索引位置i小于当前字符数组长度,意味着在当前字符串中找到了oldChar18        if (i < len) {19            //初始化字符串长度的字符数组20            char buf[] = new char[len];21            //从0开始遍历到oldChar所在位置,将字符放入buf22            for (int j = 0; j < i; j++) {23                buf[j] = val[j];24            }25            //从oldChar索引位置i开始遍历到字符串结尾26            while (i < len) {27                //当前字符28                char c = val[i];29                //如果当前字符等于oldChar,则newChar赋值给buf[i],否则不变30                buf[i] = (c == oldChar) ? newChar : c;31                i++;32            }33            //最后根据buf数组重新new一个新的字符串实例返回34            return new String(buf, true);35        }36    }37    return this;38}
  • 根据字符串正则regex匹配字符串,返回boolean,内部实则是调用正则匹配的api方法

    1public boolean matches(String regex) {2    return Pattern.matches(regex, this);3}
  • 判断字符串是否包含指定字符序列CharSequence,内部实则是调用indexOf方法,判断返回结果是否大于-1

    1 public boolean contains(CharSequence s) {2    return indexOf(s.toString()) > -1;3}
  • 根据给定的新的子字符串replacement,替换第一个匹配给定的正则表达式regex的子字符串,内部实则调用的是Matcher类的replaceFirst方法

    1 public String replaceFirst(String regex, String replacement) {2    return Pattern.compile(regex).matcher(this).replaceFirst(replacement);3}
  • 根据给定的新的子字符串replacement,替换所有匹配给定的正则表达式regex的子字符串,内部实则调用的是Matcher类的replaceAll方法

    1 public String replaceAll(String regex, String replacement) {2    return Pattern.compile(regex).matcher(this).replaceAll(replacement);3}
  • 更加通用的字符串替换方法,将匹配到的target字符序列全部替换为replacement字符序列,内部调用的也是Matcher类的replaceAll方法

    1 public String replace(CharSequence target, CharSequence replacement) {2    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(3            this).replaceAll(Matcher.quoteReplacement(replacement.toString()));4}
  • 去除字符串前后空格

     1    public String trim() { 2    //当前字符串长度 3    int len = value.length; 4    //索引标志位 5    int st = 0; 6    //当前字符串字符数组 7    char[] val = value;     8    //从0开始遍历循环,查找到空格的字符,则索引往前+1 9    while ((st < len) && (val[st] <= ' ')) {10        st++;11    }12    //从字符串尾部开始遍历循环,查找到空格字符,则长度往后-113    while ((st < len) && (val[len - 1] <= ' ')) {14        len--;15    }16    //如果st索引大于0或者长度len小于总长度,则返回裁剪字符串st偏移量开始,裁剪len长度,否则直接返回当前字符串对象17    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;18}
  • 字符串转化toString,继承自Object重写的方法,直接返回当前字符串对象

    1 public String toString() {2    return this;3}
  • 字符串转化为字符数组

    1  public char[] toCharArray() {2    //初始化字符串长度的字符数组3    char result[] = new char[value.length];4    //将字符串本身的字符数组拷贝至result[]并返回结果5    System.arraycopy(value, 0, result, 0, value.length);6    return result;7}

String 静态方法

  • 不对外公开的内部静态方法,从字符串source指定索引fromIndex开始遍历,从偏移量sourceOffset,在原始字符串长度sourceCount范围内查找目标字符串target中偏移量targetOffset开始,长度为targetCount的字符串索引第一次出现的位置。

     1static int indexOf(char[] source, int sourceOffset, int sourceCount, 2        char[] target, int targetOffset, int targetCount, 3        int fromIndex) { 4    //如果起始位置大于等于源字符串指定长度 5    if (fromIndex >= sourceCount) { 6        //如果目标字符串查找的长度为0,则直接返回源字符串长度,否则返回-1表示未找到 7        return (targetCount == 0 ? sourceCount : -1); 8    } 9    //起始位置小于010    if (fromIndex < 0) {11        //重置为012        fromIndex = 0;13    }14    //目标字符串长度为0,代表为空字符串”“15    if (targetCount == 0) {16        //直接返回起始位置17        return fromIndex;18    }19    //目标字符串第一个字符20    char first = target[targetOffset];21    //从源字符偏移量开始,计算最大的遍历次数22    int max = sourceOffset + (sourceCount - targetCount);23    //遍历24    for (int i = sourceOffset + fromIndex; i <= max; i++) {25        //循环找出第一个字符26        if (source[i] != first) {27            while (++i <= max && source[i] != first);28        }29        //todo 这段暂时没看明白 by zhangshaolin30        if (i <= max) {31            int j = i + 1;32            int end = j + targetCount - 1;33            for (int k = targetOffset + 1; j < end && source[j]34                    == target[k]; j++, k++);35            if (j == end) {36                /* Found whole string. */37                return i - sourceOffset;38            }39        }40    }41    //最终没找到 则返回-142    return -1;43}
  • 不对外公开的静态方法,上述方法的另一个重载形式,内部实则直接调用的上述方法,targetCount默认传入target.value.length

    1   static int indexOf(char[] source, int sourceOffset, int sourceCount,2        String target, int fromIndex) {3    return indexOf(source, sourceOffset, sourceCount,4                   target.value, 0, target.value.length,5                   fromIndex);6}
  • 不对外公开的内部静态方法,从字符串source指定索引fromIndex开始遍历,从偏移量sourceOffset,在原始字符串长度sourceCount范围内查找目标字符串target中偏移量targetOffset开始,长度为targetCount的字符串索引第一次出现的位置。

     1 static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, 2        char[] target, int targetOffset, int targetCount, 3        int fromIndex) { 4    //源字符长度-目标字符长度,获取起始位置 5    int rightIndex = sourceCount - targetCount; 6    //起始位置小于0,直接返回-1表示未找到目标 7    if (fromIndex < 0) { 8        return -1; 9    }10    //如果形参起始位置大于计算的实际起始位置,则直接赋值给fromIndex11    if (fromIndex > rightIndex) {12        fromIndex = rightIndex;13    }14    //如果目标字符串长度为0,表示为空字符串,则直接返回起始位置15    if (targetCount == 0) {16        return fromIndex;17    }18    //获取目标字符串最后一个索引位置19    int strLastIndex = targetOffset + targetCount - 1;20    //获取目标字符串最后一个字符21    char strLastChar = target[strLastIndex];22    //获取最小遍历次数23    int min = sourceOffset + targetCount - 1;24    //最小遍历次数+起始位置25    int i = min + fromIndex;26//循环查找最后一个字符27startSearchForLastChar:28    while (true) {29        while (i >= min && source[i] != strLastChar) {30            i--;31        }32        //如果i<min,则代表查找不到最后一个字符 返回-133        if (i < min) {34            return -1;35        }36        //todo 这段逻辑暂时没看明白 by zhangshaolin37        int j = i - 1;38        int start = j - (targetCount - 1);39        int k = strLastIndex - 1;40        while (j > start) {41            if (source[j--] != target[k--]) {42                i--;43                //找不到,继续跳过外层循环44                continue startSearchForLastChar;45            }46        }47        return start - sourceOffset + 1;48    }49}
  • 不对外公开的静态方法,上述方法的另一个重载形式,内部实则直接调用的上述方法,targetCount默认传入target.value.length

    1 static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,2        String target, int fromIndex) {3    return lastIndexOf(source, sourceOffset, sourceCount,4                   target.value, 0, target.value.length,5                   fromIndex);6}
  • 将任意Object对象转化为字符串对象返回,内部实则也是调用的ObjecttoString方法,返回结果取决于该方法的具体实现

    1  public static String valueOf(Object obj) {2    //如果obj为空,则返回"null",否则返回对象的toString返回的字符串结果3    return (obj == null) ? "null" : obj.toString();4}
  • 将字符数组转化为字符串对象返回,内部实际是用字符数组为参数 重新 new 了一个新的字符串对象,并返回

    1public static String valueOf(char data[]) {2    return new String(data);3}
  • 将字符数组转化为字符串对象返回,同时指定索引偏移量offset,截取的长度count,内部实际是重新 new 了一个新的字符串对象,并返回

    1 public static String valueOf(char data[], int offset, int count) {2    return new String(data, offset, count);3}
  • 与上一个方法效果一致,只是方法名称不同罢了

    1 public static String copyValueOf(char data[], int offset, int count) {2    return new String(data, offset, count);3}
  • valueOf(char data[])效果一致,只是方法名称不同罢了

    1 public static String copyValueOf(char data[]) {2    return new String(data);3}
  • boolean类型数据转化为字符串对象返回

    1 public static String valueOf(boolean b) {2    //为真 则返回"true" 否则返回"false"3    return b ? "true" : "false";4}
  • 将字符转化为字符串对象返回

    1 public static String valueOf(char c) {2    //初始化字符数组3    char data[] = {c};4    //重新new一个新的字符串对象返回5    return new String(data, true);6}
  • 将int数据转换为字符串对象返回,内部实际是调用的Integer.toString()方法

    1 public static String valueOf(int i) {2    return Integer.toString(i);3}
  • 将long数据转换为字符串对象返回,内部实际是调用的Long.toString()方法

    1 public static String valueOf(long l) {2    return Long.toString(l);3}
  • 将float数据转换为字符串对象返回,内部实际是调用的Float.toString()方法

    1 public static String valueOf(float f) {2    return Float.toString(f);3}
  • 将double数据转换为字符串对象返回,内部实际是调用的Double.toString()方法

    1 public static String valueOf(double d) {2    return Double.toString(d);3}

简单总结

  • String源码全部大致过了一遍之后,感慨 jdk 代码设计的强大,几天时间要完全看懂是不容易的,目前也还有很多地方没有完全明白
  • 源码并不可怕,可怕的是自己的畏惧心理,认为源码很难啃不动,其实不然,下定决心看下去,遇到不懂的可以先pass,后面再回头看可能就豁然开朗了。
  • String 内部本质就是操作字符数组 value[]
  • 因为本质就是操作字符数组,内部用到了大量的Arrays.copyOf,以及System.arraycopy方法

最后

看源码不易,如果文中有错误之处,还请留言指出,一起学习,一起进步,谢谢!

更多原创文章会第一时间推送公众号【张少林同学】,欢迎关注!

转载于:https://www.cnblogs.com/zhangshaolin/p/10239563.html

String 源码浅析————终结篇相关推荐

  1. hive 强转为string_String 源码浅析————终结篇

    写在前面 说说这几天看源码的感受吧,其实 jdk 中的源码设计是最值得进阶学习的地方.我们在对 api 较为熟悉之后,完全可以去尝试阅读一些 jdk 源码,打开 jdk 源码后,如果你英文能力稍微过得 ...

  2. Android应用Preference相关及源码浅析(Preference组件家族篇)

    | public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) | @ ...

  3. Gradle 庖丁解牛(构建源头源码浅析)

    1 背景 陆陆续续一年多,总是有人问 Gradle 构建,总是发现很多人用 Gradle 是迷糊状态的,于是最近准备来一个"Gradle 庖丁解牛"系列,一方面作为自己的总结,一方 ...

  4. hashmap允许null键和值吗_hashMap底层源码浅析

    来源:https://blog.csdn.net/qq_35824590/article/details/111769203 hashmap是我们经常使用的一个工具类.那么知道它的一些原理和特性吗? ...

  5. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 TaskMasger 启动

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [四] 上一篇: [flink]Flink 1.12.2 源码浅析 : yarn-per-job模式解析 Jo ...

  6. openedge-hub模块请求处理源码浅析——百度BIE边缘侧openedge项目源码阅读(2)

    前言 在openedge-hub模块启动源码浅析--百度BIE边缘侧openedge项目源码阅读(1)一文中浅析了openedge-hub模块的启动过程,openedge-hub为每一个连接的请求创建 ...

  7. 深入探索Android 启动优化(七) - JetPack App Startup 使用及源码浅析

    本文首发我的微信公众号:徐公,想成为一名优秀的 Android 开发者,需要一份完备的 知识体系,在这里,让我们一起成长,变得更好~. 前言 前一阵子,写了几篇 Android 启动优化的文章,主要是 ...

  8. tio-http-server 源码浅析(二)Http请求的处理HttpRequestHandler

    前言 在上一篇<tio-http-server 源码浅析(一)HttpRequestDecoder的实现>简单分析了HttpRequestDecoder的源码,并且已经得到了HttpReq ...

  9. Android应用进程间通信之Messenger信使使用及源码浅析

    转载: http://blog.csdn.net/yanbober 1 背景 这个知识点是个low货,刚开始其实想在之前一篇文章<Android异步消息处理机制详解及源码分析>一文中作为一 ...

  10. Android Loader机制全面详解及源码浅析

    原文出处:csdn@工匠若水,http://blog.csdn.net/yanbober/article/details/48861457 一.概述 在Android中任何耗时的操作都不能放在UI主线 ...

最新文章

  1. OSSIM系统的安装教程(超详细)
  2. 分布式系统唯一ID生成方案汇总
  3. 如何手动删除一个business document和pricing document的relationship
  4. 世道变了,面试初级Java开发会问到Arrays!!!你不会还不知道吧!
  5. python中的np array函数_numpy中的np.ascontiguousarray()函数
  6. “百度云手机”旗舰版发布,堪比旗舰真机?只需77元/月!
  7. time_t 和 struct tm 及时间戳的正确用法
  8. qt UI design tips
  9. springBoot项目首页居然还有这么多种玩儿法,index.html并不是必须的
  10. 调用css样式是不调用某个属性,CSS选择器可以引用另一个选择器属性吗?
  11. rs485如何使用_气体检测仪rs485和4-20ma接线方式有什么区别,该如何选择最优的接线方式...
  12. php评论表情包怎么引入,纯代码实现WordPress添加评论表情(心情)的教程
  13. 非华为电脑实现多屏协同、一碰传
  14. Flutter面试问题总结
  15. 计算机中使用资源叫什么,在计算机术语中,什么叫资源子网和通信子网?
  16. 矩阵论(补充知识):特征多项式的展开式
  17. Burp suite - Burp Clickbandit
  18. message——UVM
  19. google全屏快捷方式 关键字 kiosk
  20. ValueError: Cannot have number of splits n_splits=10 greater than the number of samples: 0

热门文章

  1. 分享一个特别好用的站长在线工具箱
  2. linux操作系统没声音,Linux系统下没有声音的解决方案
  3. 能“干掉”苹果的中国“黑客”
  4. 免费的二维码图片生成API接口和使用
  5. 二维码在线生成接口API
  6. 2011年6个微博营销趋势
  7. LaTeX 参考文献的处理
  8. OSI模型工作模式解析
  9. php base64 转 amr,base64转amr文件
  10. KVM或openstack虚拟化环境中windows主机忘记登陆密码如何使用pe的方式进行破解