Анализ исходного кода строк — заключительная глава

Java

написать впереди

Расскажите об ощущении от просмотра исходного кода в наши дни, на самом делеjdkДизайн исходного кода наиболее достоин углубленного изучения. мы правыapiПосле того, как вы более знакомы с этим, вы можете попробовать прочитать некоторыеjdkисходный код, открытыйjdkПосле исходного кода, если ваши знания английского языка немного приличны, в исходном коде есть довольно подробные комментарии, чтобы рассказать вамapiзначение, конкретное использование. Предположим, вы вдруг что-то забыли в процессе написания кода.apiИспользование API, поэтому некоторые новички, которые не читали исходный код, могут легко открыть Baidu или Google, как использовать API поиска? Хахаха, для гугловского программирования такое состояние может повторить ваш опыт на годnлет, если вы прочитали исходный код, вы можете сразу перейти к просмотру английских комментариев к исходному коду, вспомнить реализацию исходного кода и использовать его, а после прочтения исходного кода некоторые детали кода можно использовать напрямую. для справки в обычном процессе кодирования.

Там много чепухи~~ Диди, садись в машину. . .

ПредыдущийАнализ исходного кода строк (1)уже правильноStringПервая половина исходного кода разобрана, в этой статье кратко описаны оставшиеся методы...

Строковые методы-члены

  • Определить, равны ли строки, этот метод унаследован отObjectПереписанная реализация класса, в принципе, тоже сравнивает, равны ли символы в строке.

       public boolean equals(Object anObject) {
        //判断形参跟当前字符串对象地址是否相等,即是否为同一个对象,如果相等,则返回true
        if (this == anObject) {
            return true;
        }
        //如果形参为String类型对象
        if (anObject instanceof String) {
            //强转为String类型对象
            String anotherString = (String)anObject;
            //当前字符串对象的字符数组长度
            int n = value.length;
            //如果当前字符串对象的字符数组长度等于形参字符串字符数组长度
            if (n == anotherString.value.length) {
                //当前字符串字符数组
                char v1[] = value;
                //形参字符串字符数组
                char v2[] = anotherString.value;
                //遍历索引起始位置0
                int i = 0;
                //遍历当前字符串字符数组,每个索引位置的字符与形参字符串索引位置字符比较,如果不相等则返回false
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        //以上条件都不满足,最后返回false
        return false;
    }
    
  • входящийCharSequenceпараметр интерфейса, который на самом деле совпадает сStringBuffer,StringBuilderсравнивает на равенство, потому чтоStringBuffer,StringBuilderвсе сбудетсяCharSequenceинтерфейс

    public boolean contentEquals(CharSequence cs) {
        //判断形参是否是AbstractStringBuilder抽象类,实则因当传入的是其子类:StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            //如果形参是StringBuffer类型对象
            if (cs instanceof StringBuffer) {
                //同步锁,调用nonSyncContentEquals方法比较两种是否相等
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                //如果形参对象是StringBuilder,则调用nonSyncContentEquals方法比较两种是否相等
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // 如果形参是String对象,则直接调用equals方法返回
        if (cs instanceof String) {
            return equals(cs);
        }
        // 如果是其他的CharSequence实现类,则遍历,一个个字符进行比较,找到一个字符不相等则直接返回false
        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;
            }
        }
        //以上代码都不成立,走到最后直接返回true
        return true;
    }
    
  • Приватный метод, асинхронный метод (thread unsafe) сравнивает с AbstractStringBuilder на равенство, фактически сравнивает размер со своим подклассом: StringBuffer, StringBuilder,contentEquals(CharSequence cs)Основной код сравнения в методе заключается в вызове этого метода.

      private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
        //当前字符串对象字符数组
        char v1[] = value;
        //获取形参字符数组
        char v2[] = sb.getValue();
        //当前字符串对象字符数组长度
        int n = v1.length;
        //如果当前字符串对象字符数组长度不等于形参字符数组长度,则直接返回false
        if (n != sb.length()) {
            return false;
        }
        //遍历当前字符串对象字符数组,与形参字符数组逐一比较字符,找到一个字符不相等,则直接返回false
        for (int i = 0; i < n; i++) {
            if (v1[i] != v2[i]) {
                return false;
            }
        }
        //以上条件都不成立,代码走到最后则直接返回true
        return true;
    }
    
  • общедоступные методы по сравнению сStringBufferНезависимо от того, равны ли объекты, внутренний фактический вызов вызывается напрямую.contentEquals(CharSequence cs)метод, который можно назватьStringBufferспециальное издание.

      public boolean contentEquals(StringBuffer sb) {
        return contentEquals((CharSequence)sb);
    }
    
  • Соответствует, равны ли два частичных фрагмента строки

      public boolean regionMatches(int toffset, String other, int ooffset,
            int len) {
        //当前字符串字符数组
        char ta[] = value;
        //当前字符串开始比较的起始位置,即偏移量
        int to = toffset;
        //待比较的字符串字符数组
        char pa[] = other.value;
        //待比较的字符串起始位置,即偏移量
        int po = ooffset;
        //索引检查 1.偏移量小于0  2. 偏移量大于总长度-待比较的长度
        //以上两种情况直接返回false
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        //遍历,找出不相等的字符,则返回false
        while (len-- > 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        //不出意外,最终则返回true
        return true;
    }
    
  • Сопоставьте, равны ли две части строки, и решите, следует ли игнорировать регистр

    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;
        //索引检查 1.偏移量小于0  2. 偏移量大于总长度-待比较的长度
        //以上两种情况直接返回false
        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) {
                //字符转换为大写
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                //如果相等,则继续跳过
                if (u1 == u2) {
                    continue;
                }
                //转换为小写进行比较,如果相等则继续跳过
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            //否则发现不相等,则直接返回false
            return false;
        }
        //不出意外,最终返回true
        return true;
    }
    
  • Сравнивайте размеры строк независимо от регистра

     public boolean equalsIgnoreCase(String anotherString) {
        //一句三目运算直接搞定
        //如果当前字符串对象地址与形参字符串相等,则返回true
        //否则判断形参字符串是否为空,形参字符串长度是否与当前字符串长度相等,直接调用regionMatches比较两个字符串所有字符是否相等,同时忽略大小写比较
        //以上全部为true则相等
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }
    
  • Сравнивает две строки на равенство, этот метод реализует сам себяComparableИнтерфейс, возвращает результат типа int, равный 0, строки равны, меньше 0, первое меньше второго, больше 0, первое больше второго

      public int compareTo(String anotherString) {
        //当前字符串字符数组长度
        int len1 = value.length;
        //待比较字符串字符数组长度
        int len2 = anotherString.value.length;
        //获取较小的长度
        int lim = Math.min(len1, len2);
        //当前字符串字符数组
        char v1[] = value;
        //待比较的字符串字符数组
        char v2[] = anotherString.value;
        //索引位置0开始
        int k = 0;
        //遍历较小的字符数组
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            //如果字符不相等
            if (c1 != c2) {
                //返回字符之差
                return c1 - c2;
            }
            k++;
        }
        //如果字符都相等,则返回长度之差
        return len1 - len2;
    }
    
  • Сравните два размера строки без учета регистра, используя компаратор по умолчанию.

    //初始化默认的比较器
    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    //默认的比较器,不区分大小写                          
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;
    
        public int compare(String s1, String s2) {
            //第一个字符串长度
            int n1 = s1.length();
            //第二个字符串长度
            int n2 = s2.length();
            //取小
            int min = Math.min(n1, n2);
            //遍历较小的字符串
            for (int i = 0; i < min; i++) {
                //获取指定索引字符
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                //如果字符不相等
                if (c1 != c2) {
                    //转化为大写
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    //转化为大写后比较,不相等
                    if (c1 != c2) {
                        //转化为小写继续比较
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        //转化为小写字符,不相等
                        if (c1 != c2) {
                            //直接返回字符之差
                            return c1 - c2;
                        }
                    }
                }
            }
            //不出意外,最终返回长度之差
            return n1 - n2;
        }
    
        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }
    
    //内部直接调用默认比较器的compare方法
    public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }
    
  • Начиная с указанного смещения, определите, следует ли начинать с указанной строки

     public boolean startsWith(String prefix, int toffset) {
        //当前字符串字符数组
        char ta[] = value;
        //偏移量
        int to = toffset;
        //指定字符串前缀字符数组
        char pa[] = prefix.value;
        //索引位置0开始
        int po = 0;
        //指定字符串前缀数组长度
        int pc = prefix.value.length;
        //偏移量小于0 或者 //偏移量大于总长度-字符串前缀长度,则直接返回false
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        //遍历前缀字符串
        while (--pc >= 0) {
            //从偏移量开始检索,找到字符不相等,则返回false
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        //不出意外,最后则返回true
        return true;
    }
    
  • С начала строки определить, начинается ли она с указанной строки

     public boolean startsWith(String prefix) {
        //直接调用startsWith重载方法,偏移量为0
        return startsWith(prefix, 0);
    }
    
  • Чтобы определить, заканчивается ли она указанной строкой, внутри напрямую вызывается метод startWith, а смещение представляет собой общую длину строки — длину строки суффикса.

    public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }
    
  • Ищет позицию индекса первого вхождения указанного символа в строку, начиная с указанного смещения

     public int indexOf(int ch, int fromIndex) {
        //当前字符串字符数组长度
        final int max = value.length;
        //如果偏移量小于0,则重置为0
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            //偏移量大于总长度,则返回-1,意味着找不到指定字符
            return -1;
        }
    
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            //当前字符串字符数组
            final char[] value = this.value;
            //从偏移量位置开始遍历
            for (int i = fromIndex; i < max; i++) {
                //找到相等的字符,则返回索引
                if (value[i] == ch) {
                    return i;
                }
            }
            //找不到则返回-1
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }
    
  • Найдите позицию индекса первого вхождения указанного символа в строку, начиная со смещения 0 и проходя поиск

     public int indexOf(int ch) {
        return indexOf(ch, 0);
    }
    
  • Найти позицию индекса последнего вхождения указанного символа в строку, начиная с указанного смещения

      public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            //当前字符串字符数组
            final char[] value = this.value;
            //偏移量与字符串最后的位置取小
            int i = Math.min(fromIndex, value.length - 1);
            //从后遍历字符数组
            for (; i >= 0; i--) {
                //找到相等的字符,返回索引
                if (value[i] == ch) {
                    return i;
                }
            }
            //找不到则返回-1
            return -1;
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }
    
  • Найти позицию индекса последнего вхождения указанного символа в строку, начиная с последней позиции индекса строки для прохождения поиска

     public int lastIndexOf(int ch) {
        return lastIndexOf(ch, value.length - 1);
    }
    
  • Начиная с указанной позиции, найти позицию индекса первого вхождения строки в исходной строке, которая фактически вызывается непосредственно внутри.indexOfвнутренний статический метод

      public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    
  • Найдите позицию индекса первого вхождения строки в исходной строке, и приведенное выше фактически вызывается напрямую.indexOfметод,fromIndexПо умолчанию начинается с 0

     public int indexOf(String str) {
        return indexOf(str, 0);
    }
    
  • Начиная с указанной позиции, найдите позицию индекса последнего вхождения строки в исходной строке, которая фактически вызывается непосредственно внутри.lastIndexOfвнутренний статический метод

     public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    
  • Найдите позицию индекса последнего вхождения строки в исходной строке, которая на самом деле вызывается непосредственно вышеlastIndexOfметод,fromIndexПо умолчанию отvalue.lengthНачинать

    public int lastIndexOf(String str) {
        return lastIndexOf(str, value.length);
    }
    
  • Обрезать строку в соответствии с указанным интервалом и вернуть подстроку,beginIndexисходное положение (включительно),endIndexконечное положение (не включено)

        public String substring(int beginIndex, int endIndex) {
        //起始位置小于0,抛出索引越界异常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //结束位置大于字符串总长度,则抛出索引越界异常
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        //待截取的字符串长度
        int subLen = endIndex - beginIndex;
        //待截取的字符串长度小于0,则抛出索引越界异常
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //三目判断 起始位置等于0,并且结束位置等于字符串长度,则表示为截取总长度,返回当前字符串对象
        //否则重新new一个字符串实例,从beginIndex开始,截取subLen长度
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
    
  • из исходного положенияbeginIndexНачать перехватывать исходную строку до конца, возвращая подстроку

     public String substring(int beginIndex) {
        //起始位置小于0,抛出索引越界异常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //待截取的字符串长度
        int subLen = value.length - beginIndex;
        //待截取的字符串长度小于0,则抛出索引越界异常
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //三目判断 起始位置等于0,则表示为截取总长度,返回当前字符串对象,否则重新new一个新的字符串实例,从beginIndex开始,截取subLen长度
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
    
  • Обрезать строку в соответствии с указанным интервалом и вернутьCharSequenceинтерфейс,beginIndexисходное положение (включительно),endIndexКонечное положение (не включено), которое фактически вызывается непосредственно внутриsubstringпросто возвращает интерфейс верхнего уровня.

     public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }
    
  • Сращивание строк, сращивание целевой строки в конце и возврат новой строки

      public String concat(String str) {
        //待拼接的字符串长度
        int otherLen = str.length();
        //如果待拼接的字符串长度等于0,则直接返回当前字符串对象
        if (otherLen == 0) {
            return this;
        }
        //当前字符串长度
        int len = value.length;
        //将当前字符串字符数组拷贝到新的字符数组buf[]中,长度扩容至len + otherLen
        char buf[] = Arrays.copyOf(value, len + otherLen);
        //将待拼接的字符数组拷贝至buf[]中,从len开始,理论上这部操作完之后,字符数组已经拼接成功了
        str.getChars(buf, len);
        //利用最新的字符数组,重新new一个新的字符串实例返回
        return new String(buf, true);
    }
    
  • Преобразовать указанный символ в строкуoldCharзаменить на новый символnewChar

      public String replace(char oldChar, char newChar) {
        //如果旧的字符跟新的字符不相等,才执行替换逻辑,否则直接返回当前字符串对象
        if (oldChar != newChar) {
            //当前字符串长度
            int len = value.length;
            //索引从-1开始
            int i = -1;
            //当前字符串字符数组
            char[] val = value;
            //遍历当前字符数组,从0开始,因为++i之后等于0
            while (++i < len) {
                //找到与oldChar相等的字符,则中断循环
                if (val[i] == oldChar) {
                    break;
                }
            }
            //如果oldChar索引位置i小于当前字符数组长度,意味着在当前字符串中找到了oldChar
            if (i < len) {
                //初始化字符串长度的字符数组
                char buf[] = new char[len];
                //从0开始遍历到oldChar所在位置,将字符放入buf
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                //从oldChar索引位置i开始遍历到字符串结尾
                while (i < len) {
                    //当前字符
                    char c = val[i];
                    //如果当前字符等于oldChar,则newChar赋值给buf[i],否则不变
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                //最后根据buf数组重新new一个新的字符串实例返回
                return new String(buf, true);
            }
        }
        return this;
    }
    
  • Регулярно на основе строкregexСопоставьте строку, верните логическое значение, внутренний факт заключается в вызове API-метода регулярного сопоставления

    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }
    
  • Определяет, содержит ли строка указанную последовательность символовCharSequence, который на самом деле называется внутреннеindexOfметод, чтобы определить, больше ли возвращаемый результат -1

     public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }
    
  • Согласно заданной новой подстрокеreplacement, замените первое, которое соответствует заданному регулярному выражениюregexПодстрока , которая фактически вызывается внутриMatcherКатегорияreplaceFirstметод

     public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }
    
  • Согласно заданной новой подстрокеreplacement, заменяет все совпадения данного регулярного выраженияregexПодстрока , которая фактически вызывается внутриMatcherКатегорияreplaceAllметод

     public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
    
  • Более общий метод замены строки, который будет соответствоватьtargetВся последовательность символов заменяется наreplacementпоследовательность символов, которая также называется внутреннеMatcherКатегорияreplaceAllметод

     public String replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }
    
  • Удалить пробелы до и после строки

        public String trim() {
        //当前字符串长度
        int len = value.length;
        //索引标志位
        int st = 0;
        //当前字符串字符数组
        char[] val = value;    
        //从0开始遍历循环,查找到空格的字符,则索引往前+1
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        //从字符串尾部开始遍历循环,查找到空格字符,则长度往后-1
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        //如果st索引大于0或者长度len小于总长度,则返回裁剪字符串st偏移量开始,裁剪len长度,否则直接返回当前字符串对象
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }
    
  • преобразование строкtoString, унаследовано отObjectПереопределенный метод для прямого возврата текущего строкового объекта

     public String toString() {
        return this;
    }
    
  • Преобразование строки в массив символов

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

Струнный статический метод

  • Внутренний статический метод, не открытый извне, из строкиsourceуказанный индексfromIndexначать обход, начиная со смещенияsourceOffset, в исходной длине строкиsourceCountНайдите целевую строку в диапазонеtargetсреднее смещениеtargetOffsetначало, длинаtargetCountПозиция индекса строки первого вхождения.

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        //如果起始位置大于等于源字符串指定长度
        if (fromIndex >= sourceCount) {
            //如果目标字符串查找的长度为0,则直接返回源字符串长度,否则返回-1表示未找到
            return (targetCount == 0 ? sourceCount : -1);
        }
        //起始位置小于0
        if (fromIndex < 0) {
            //重置为0
            fromIndex = 0;
        }
        //目标字符串长度为0,代表为空字符串”“
        if (targetCount == 0) {
            //直接返回起始位置
            return fromIndex;
        }
        //目标字符串第一个字符
        char first = target[targetOffset];
        //从源字符偏移量开始,计算最大的遍历次数
        int max = sourceOffset + (sourceCount - targetCount);
        
        //遍历
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            //循环找出第一个字符
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
            
            //todo 这段暂时没看明白 by zhangshaolin
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
    
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        //最终没找到 则返回-1
        return -1;
    }
    
  • Статический метод, который не открыт для внешнего мира, другая перегруженная форма вышеуказанного метода и вышеуказанный метод, который напрямую вызывается внутри,targetCountВходящий по умолчаниюtarget.value.length

       static int indexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return indexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }
    
  • Внутренний статический метод, не открытый извне, из строкиsourceуказанный индексfromIndexначать обход, начиная со смещенияsourceOffset, в исходной длине строкиsourceCountНайдите целевую строку в диапазонеtargetсреднее смещениеtargetOffsetначало, длинаtargetCountПозиция индекса строки первого вхождения.

     static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        
        //源字符长度-目标字符长度,获取起始位置
        int rightIndex = sourceCount - targetCount;
        //起始位置小于0,直接返回-1表示未找到目标
        if (fromIndex < 0) {
            return -1;
        }
        //如果形参起始位置大于计算的实际起始位置,则直接赋值给fromIndex
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }
        //如果目标字符串长度为0,表示为空字符串,则直接返回起始位置
        if (targetCount == 0) {
            return fromIndex;
        }
        //获取目标字符串最后一个索引位置
        int strLastIndex = targetOffset + targetCount - 1;
        //获取目标字符串最后一个字符
        char strLastChar = target[strLastIndex];
        //获取最小遍历次数
        int min = sourceOffset + targetCount - 1;
        //最小遍历次数+起始位置
        int i = min + fromIndex;
    
    //循环查找最后一个字符
    startSearchForLastChar:
        while (true) {
            while (i >= min && source[i] != strLastChar) {
                i--;
            }
            //如果i<min,则代表查找不到最后一个字符 返回-1
            if (i < min) {
                return -1;
            }
            //todo 这段逻辑暂时没看明白 by zhangshaolin
            int j = i - 1;
            int start = j - (targetCount - 1);
            int k = strLastIndex - 1;
    
            while (j > start) {
                if (source[j--] != target[k--]) {
                    i--;
                    //找不到,继续跳过外层循环
                    continue startSearchForLastChar;
                }
            }
            return start - sourceOffset + 1;
        }
    }
    
  • Статический метод, который не открыт для внешнего мира, другая перегруженная форма вышеуказанного метода и вышеуказанный метод, который напрямую вызывается внутри,targetCountВходящий по умолчаниюtarget.value.length

     static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return lastIndexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }
    
  • любойObjectОбъект преобразуется в строковый объект и возвращается, а внутренняя реальность также называетсяObjectизtoStringметод, возвращаемый результат зависит от конкретной реализации метода

      public static String valueOf(Object obj) {
        //如果obj为空,则返回"null",否则返回对象的toString返回的字符串结果
        return (obj == null) ? "null" : obj.toString();
    }
    
  • Преобразуйте массив символов в объект строки и верните его.Внутренне массив символов используется в качестве параметра для повторного создания нового объекта строки и возврата

    public static String valueOf(char data[]) {
        return new String(data);
    }
    
  • Преобразуйте массив символов в строковый объект и верните его, указав при этом смещение индекса.offset, длина усеченногоcount, который фактически обновляет новый строковый объект и возвращает

     public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }
    
  • Эффект такой же, как у предыдущего метода, но имя метода другое.

     public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }
    
  • иvalueOf(char data[])Эффект тот же, только имя метода другое.

     public static String copyValueOf(char data[]) {
        return new String(data);
    }
    
  • будетbooleanДанные типа преобразуются в строковый объект и возвращаются

     public static String valueOf(boolean b) {
        //为真 则返回"true" 否则返回"false"
        return b ? "true" : "false";
    }
    
  • Преобразование символа в строковый объект и возврат

     public static String valueOf(char c) {
        //初始化字符数组
        char data[] = {c};
        //重新new一个新的字符串对象返回
        return new String(data, true);
    }
    
  • Преобразуйте данные int в строковый объект и верните его, который фактически вызывается внутриInteger.toString()метод

     public static String valueOf(int i) {
        return Integer.toString(i);
    }
    
  • Преобразуйте длинные данные в строковый объект и верните его, который фактически вызывается внутриLong.toString()метод

     public static String valueOf(long l) {
        return Long.toString(l);
    }
    
  • Преобразуйте данные с плавающей запятой в строковый объект и верните его, который фактически вызывается внутриFloat.toString()метод

     public static String valueOf(float f) {
        return Float.toString(f);
    }
    
  • Преобразуйте двойные данные в строковый объект и верните его, который фактически вызывается внутриDouble.toString()метод

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

простое резюме

  • ПучокStringПримерно просмотрев весь исходный код, я вздохнул от умиленияjdkДизайн кода мощный, полностью понять его за несколько дней непросто, и еще есть много мест, которые не до конца поняты.
  • Исходный код не страшный.Страшно то, что я боюсь.Я думаю, что исходный код трудно разжевать.На самом деле это не так.Я решаюсь прочитать его.pass, Оглядываясь на это позже, это может внезапно стать ясным.
  • StringВнутренняя суть заключается в манипулировании символьными массивамиvalue[]
  • Поскольку суть заключается в манипулировании символьными массивами, большое количество внутреннихArrays.copyOf,а такжеSystem.arraycopyметод

Наконец

Нелегко читать исходный код.Если в тексте есть ошибки, пожалуйста, оставьте сообщение, чтобы указать, учитесь и добивайтесь прогресса вместе, спасибо!

Больше оригинальных статей будет размещено в общедоступном аккаунте [Чжан Шаолинь] как можно скорее, добро пожаловать на внимание!

公众号【张少林同学】