Java字符串String类学习笔记2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012934325/article/details/83865997

Java字符串String类学习笔记一 ,这篇文章主要学习了String的域及以下的几个几个方法:

  1. int length()
  2. isEmpty()
  3. charAt(int index)
  4. getBytes(String charsetName)
  5. contentEquals(StringBuffer sb)
  6. regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
  7. compareTo(String anotherString)
  8. compareToIgnoreCase(String str)

接下来的这篇文章我会学习String类的如下几个方法以及其重载的方法:

  1. boolean startsWith(String prefix, int toffset)

  2. boolean endsWith(String suffix)

  3. int hashCode()

  4. int indexOf(int ch, int fromIndex)

  5. int lastIndexOf(int ch, int fromIndex)

  6. int indexOf(String str, int fromIndex)

  7. int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)

  8. int lastIndexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)

  9. String substring(int beginIndex)

  10. String substring(int beginIndex, int endIndex)

  11. CharSequence subSequence(int beginIndex, int endIndex)

  12. String concat(String str)

  13. String replace(char oldChar, char newChar)

  14. boolean matches(String regex)

  15. boolean contains(CharSequence s)

  16. String replaceFirst(String regex, String replacement)

  17. String replaceAll(String regex, String replacement)

  18. String replace(CharSequence target, CharSequence replacement)

  19. String[] split(String regex, int limit)

  20. static String join(CharSequence delimiter, CharSequence... elements)

  21. static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

  22. String toLowerCase(Locale locale)

  23. String toUpperCase(Locale locale)

  24. String trim()

  25. String toString()

  26. char[] toCharArray()

  27. static String format(String format, Object... args)

  28. static String format(Locale l, String format, Object... args)

  29. static String valueOf(Object obj)

  30. static String valueOf(char data[])

  31. static String valueOf(char data[], int offset, int count)

  32. static String copyValueOf(char data[], int offset, int count)

  33. static String copyValueOf(char data[])

  34. static String valueOf(boolean b)

  35. static String valueOf(int i)

  36. static String valueOf(long l)

  37. static String valueOf(float f)

  38. static String valueOf(double d)

  39. native String intern()


上面的方法基本我都会看看源码,有没看懂的我也会写在文章中,还希望大家可以共同学习探讨,互相学习。

String类有一个静态的方法,也就是可以直接用类名.方法名的形式调用,这个方法是valueOf(param),该方法又一个参数,可以是int,long,float,boolean,double基础类型,调用该方法可以将基础类型转为字符串类型,实现方法就是各自的valueOf方法中用基础类型对应的包装类,调用toString()方法来进行转换,这里只看其中一个的源码,如下所示:

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

此处需要注意的是,当你调用String的valueOf方法时,你应该判断即将转为字符串的内容是否为null,如果为null,调用该方法就会报NullPointException异常;如果不为null,则可以调用该方法将其转为字符串。下面是当内容为null时,报空指针异常的代码:

public class TestString {
    public static  void main(String[] args){
        System.out.println(String.valueOf(null));
    }
}

异常:

Exception in thread "main" java.lang.NullPointerException
	at java.lang.String.<init>(String.java:166)
	at java.lang.String.valueOf(String.java:3008)
	at com.java.lee.TestString.main(TestString.java:11)
 public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }

boolean startsWith(String prefix)这个方法是我经常会在开发中用到的,来判断字符串是否以某个字符或者某些字符开始的,来看一下它的实现,通过源码,我们可以看到他调用了boolean startsWith(String prefix,int index)这个方法,第一个参数是要判断以什么字符开头,第二个参数传的是0,表示是从这个字符串的开头来做匹配,如果匹配到则返回true,否则返回false。

下面我们来看一下方法boolean startsWith(String prefix, int toffset)的源码:

public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = toffset;
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1>>>1.
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

该方法有两个参数,我在前面也已经介绍过了,首先是判断传入的索引位置,如果该索引值小于0或者大于字符串的长度,则直接返回false,否则进行下一步的判断;这个循环的终止条件就是当传入的字符串的长度递减小于0时,终止循环,字符数组ta表示的是原字符串的字符数组表示,字符数组pa表示的是匹配的字符串前缀数组表示,因为是循环遍历数组,所以要防止数组越界,所以临界条件就是pc的值。

public boolean endsWith(String suffix) { return startsWith(suffix, value.length - suffix.value.length); }

boolean endsWith(String suffix)该方法表示字符串以某字符结尾,里面具体是调用了startsWith方法,第一个参数还是结尾判断的子字符串,第二个参数是字符串的长度与子字符串长度的差值,也就是说,做比较的时候,是从差值的索引在原字符串中取值与子字符串的第一个字符做比较,其余字符以此类推。

此处你可以这样理解第二个参数的传值,比如第一个字符串是abcdef,第二个子字符串是ef,我们要判断前者是否以后者为后缀结尾的,那么我们就需要知道从原字符串的哪里做比较,按照索引值来说,我们应该从第一个字符串的索引为4的地方开始,这正好也是原字符串与子字符串的长度差值,所以第二个参数值的来源就是因为这个原因。

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

hashCode()该方法主要是用来返回字符串的哈希值,主要是按照for循环中的那个计算来进行返回。

 public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i < max; i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }

int indexOf(int ch, int fromIndex)该方法有两个参数,第一个参数是字符的unicode value,你可以通过unicode表来查找,链接如下所示:unicode characters,第二个参数表示的是索引,比如一个字符串中有多个字符组成,每个字符的unicode value是不相同的,所以我们如果想知道某个字符第几次出现在这个字符串中,我们可以用该值,实现思路:

  1. 获取字符串的长度
  2. 判断第二个参数fromIndex,如果小于0,则按照0来算;如果大于等于字符串的长度,则返回-1;其余的情况执行下面的if条件判断。
  3. value字符数组的内容就是字符串的字符数组表示形式,然后从fromIndex开始循环,一直循环完这个字符串,如果索引i的值与传入的unicode point的值相等,则返回该索引,否则返回-1,结束方法。

下面举个例子,这个例子你也可以在youtobe上面看到:

public class TestString {
    public static  void main(String[] args){
       String str = "JAVA";
       //A的unicode point值为65
       System.out.println(str.codePointAt(1));
       //返回值为1
       System.out.println(str.indexOf(65,0));
       //返回值为3
        System.out.println(str.indexOf(65,2));
    }
}

从上面的程序片段中我们可以看出第一个打印语句调用了codePointAt(int index)方法,该方法返回了字符串中索引为1的字符的unicode point的值,然后我们分别有了下面两个打印语句,分别是看从索引为0和2 开始匹配第一个出现该字符A的索引位置。分别返回了1和3是A在字符串中的两个索引位置。

 public int codePointAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, value.length);
    }

该方法是根据传入的索引来返回字符串中该索引所对字符的unicode point值,里面调用了CharactercodePointAtImpl方法

public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid 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;
                }
            }
            return -1;
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }

lastIndexOf(int ch, int fromIndex)该方法返回的是该字符在字符串中最后一次出现的索引位置。参数ch的值就是unicode point,范围是从0到0xFFFF,两个个参数的意思分别是:

  1. ch:表示该字符的unicode code point
  2. fromIndex:表示要从该字符串的哪个位置开始搜索匹配该字符,如果该值大于或者等于字符串的长度,就相当于要搜索整个字符串来匹配该字符,注意循环,是从该字符串的末尾字符开始匹配,如果匹配到则返回该字符的索引值,如果没有匹配到,则返回-1。
 public int indexOf(String str) {
        return indexOf(str, 0);
    }

int indexOf(String str)该方法是我们在字符串中常用的操作,用来返回某个字符在字符串中首次出现的索引位置,可以用来判断字符串中是否包含该字符。通过该方法的源码我们可以看出,这个方法的参数是一个String类型的,与前面的不同前面是int类型的。它返回了indexOf(str, 0)表示调用该方法,并且第一个参数就是要查找的字符,第二个参数表示要从字符串的哪里开始查找。

 public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
public class TestString {
    public static  void main(String[] args){
       String str = "JAVA";
       //返回A在字符串中第一出现的索引位置,从字符串索引为0处开始匹配,返回值为1
       System.out.println(str.indexOf('A'));
       //返回A在字符串中第一出现的索引位置,从字符串索引为2处开始匹配,返回值为3
       System.out.println(str.indexOf('A',2));
        //返回A在字符串中第一出现的索引位置,从字符串索引为5处开始匹配,此时5大于了字符串的长度,所以返回了-1
        System.out.println(str.indexOf('A',5));
    }
}

该方法的根源实现是如下代码:

static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            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;
                }
            }
        }
        return -1;
    }

我对该方法的参数解释一下:

  1. source:是一个字符数组,表示的是该字符要在某个字符串中搜索,所搜索的字符串的字符数组表现形式就是source
  2. sourceOffset:表示要从字符数组中的哪个索引开始搜索
  3. sourceCount:原字符串的长度
  4. target:就是你要搜索的那个字符串字符数组表现形式
  5. targetOffset:表示要搜索的那个字符串字符数组哪个索引开始搜索
  6. targetCount:搜索的目标字符串的长度
  7. fromIndex:表示要从哪个索引位置开始搜索
public int lastIndexOf(String str) {
        return lastIndexOf(str, value.length);
    }
 public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
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);
    }
static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        /*
         * Check arguments; return immediately where possible. For
         * consistency, don't check for null str.
         */
        int rightIndex = sourceCount - targetCount;
        if (fromIndex < 0) {
            return -1;
        }
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }
        /* Empty string always matches. */
        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--;
            }
            if (i < min) {
                return -1;
            }
            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;
        }
    }
 public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

substring(int beginIndex)该方法是用来对字符串进行截取,参数是表示要从哪里开始截取,一直截取到字符串长度结束,截取的结果是包含参数所在位置的字符。

  1. 如果索引值小于0 则抛出异常
  2. 如果字符串的长度减掉要截取得索引值,结果小于0,则抛出异常
  3. 除了上述两种情况外,如果截取的索引为0,则返回当前字符串对象,否则就调用String类的构造方法String(value, beginIndex, subLen)来返回子字符串。

下面是该方法的demo:

public class TestString {
    public static  void main(String[] args){
       String str = "JAVA";
       //JAVA
       System.out.println(str.substring(0));
       //AVA
       System.out.println(str.substring(1));
    }
}

下面是上面substring的一个重载方法,源码如下:

public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

该方法有两个参数,第一个参数是指定要从字符串哪里开始截取,第二个字符串表示截取的字符串到哪里为止,这个方法有个特点就是,截取结果是前闭后开,意思就是截取的时候开始索引的位置字符包含在截取的内容中,而截至位置的字符是不包含在截取的内容中。下面个一个demo

public class TestString {
    public static  void main(String[] args){
       String str = "wonders group";
       //ond
       System.out.println(str.substring(1,4));
    }
}

你也可以这样理解该方法,从开始索引截取字符串,截取的长度为endIndex与beginIndex的差值。

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

String concat(String str)该方法就是将字符串进行连接,参数是你要将某个字符进行连接在调用者的尾部。如果参数的长度为0,则直接返回当前字符串对象,否则的话就调用Arrays类的copyOf方法转为字符数组,然后在调用String类的getChars(char[] ch,int len)方法来进行粘合,最后通过String类的构造方法将其进行转为字符串的形式。下面是该方法的demo:

public class TestString {
    public static  void main(String[] args){
       String str = "wonders group";
       //wonders group based in shanghai
       System.out.println(str.concat(" based in shanghai"));
    }
}
public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

String replace(char oldChar, char newChar)该方法将原有字符串中所有的oldChar字符替换为了newChar,构造了一个新的字符串返回。第一个参数是要替换的字符,第二个参数是用来替代原有字符的字符。如果oldChar在原有字符串中不存在,那么返回的结果就是原有字符串。

看一下源码的实现思路:

  1. 如果oldChar与newChar相等,则直接返回当前对象字符串;
  2. 当oldChar与newChar不相等的时候,然后进行逻辑处理,我看了一下代码的逻辑,它的实现是,先循环一次字符数组,找到第一个与oldChar相等的字符的下标,创建一个新的字符数组,然后进行一次循环,将该下标之前的所有字符全部赋值到新的字符数组中,然后开始新的一个循环,临界条件就是索引必须小于字符串的长度,此时,将原字符数组的值赋予字符变量c,然后用三目表达式来判断,如果c与oldChar相等,则返回newChar给该索引的值,否则就原样返回,变量i自增,最后返回新的字符串。
 public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }

boolean matches(String regex)该方法是用来判断字符串是否与参数中的正则表达式匹配,如果matches的话,则返回true,否则返回false。正则表达是还是需要学习和研究的,我的正则表达式很Low,所以这个方法了解一下,具体就没有demo了。

public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }

boolean contains(CharSequence s)该方法是用来判断字符串中是否包含了某个字符序列,如果包含则返回true,否则返回false。它里面的实现也是调用indexOf方法来做判断,如果能存在的话,就返回非负数,这样符合大于-1,此时contains方法就会返回true,反之就会返回false.

 public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }

String replaceFirst(String regex, String replacement)该方法是用来替换字符串中首次出现的字符序列,第一个参数可以是一个正则表达式,也可以是一个字符序列,第二个参数是新的字符序列用来替换字符串中与参数regex所匹配的第一个字符串。下面是一个小的demo程序:

String Str = new String("Welcome to Tutorialspoint.com");
        System.out.print("Return Value :" );
        //Return Value :AMROOD
        System.out.println(Str.replaceFirst("(.*)Tutorials(.*)", "AMROOD"));
        System.out.print("Return Value :" );
        //Return Value :Welcome to AMROODpoint.com
        System.out.println(Str.replaceFirst("Tutorials", "AMROOD"));
public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

String replaceAll(String regex, String replacement)该方法是用来替换字符串中所有符合条件的字符,然后返回一个新的字符串。下面对参数进行一下说明:

  1. regex:String类型,它可以是一个正则表达式,也可以是一个字符串或者字符,用来匹配原有字符串中的字符序列
  2. replacement:该参数是一个String类型,用来替换第一个参数所匹配的字符。
public String replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }

String replace(CharSequence target, CharSequence replacement)该方法也是用来替换字符串中的字符序列,只会替换匹配的目标字符,参数说明:

  1. target:要被替换的字符序列
  2. replacement:需要代替target字符序列的字符
public class TestString {
    public static  void main(String[] args){
        String Str = new String("aaabaa");
        //helloabhello
        System.out.println(Str.replace("aa","hello"));
    }
}

可以从代码中看出来,这个方法是如果匹配到了target字符,然后就用replacement进行替换,替换完之后然后再继续匹配target字符,如果还有,则继续替换,直到匹配完所有字符。

public String[] split(String regex) {
        return split(regex, 0);
    }

String[] split(String regex)该方法是用来将字符串按照正则表达式或者字符序列来进行拆分,它调用了split的重载方法,下面是该重载方法的源码

 public String[] split(String regex, int limit) {
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

split该方法会返回一个String类型的数组,数组的内容是按照第一个参数进行匹配拆分的,如果limt为0,则从字符串的开始匹配第一个参数,如果匹配到则将该字符之前的内容作为数组的一个元素,然后进行下一个的匹配,直到整个字符串遍历完毕。该数组中的元素也是按照字符串中字符出现的顺序进行显示的。如果没有匹配到的话,则返回原有的字符串。

public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

static String join(CharSequence delimiter, CharSequence... elements)该方法是String类的一个静态方法,返回值类型为String类型,有两个参数,分别是:

  1. delimiter:是一个CharSequence的字符序列,代表的是限定符;
  2. elements:是字符序列类型,它是一个可变的参数列表,表示此处可有多个参数,都是CharSequence的类型。

该方法就是用delimiter来分隔第二个参数elements元素,然后返回一个字符串。下面是一个demo示例:

public class TestString {
    public static  void main(String[] args){
        String str = " ";
        //wondersgroup based in shanghai
        System.out.println(String.join(str,"wondersgroup","based","in","shanghai"));
        List<String> list= Arrays.asList("Steve", "Rick", "Peter", "Abbey");
        String names = String.join(" | ", list);
        //Steve | Rick | Peter | Abbey
        System.out.println(names);
    }
}

下面是它的一个构造方法的源码,只是第二个参数是集合类型:

public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

通过这两个方法我们可以看出来,他的内部实现是通过创建StringJoiner来创建对象,并且循环可变参数列表,访问每一个元素,然后调用joiner的add方法进行追加,最后调用joiner的toString方法将其转为字符串。【注明:StringJoiner类是JDK1.8引入的,final修饰的不可变的类,join方法也是JDK1.8才引入进来的】

public String toLowerCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }

        int firstUpper;
        final int len = value.length;

        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstUpper = 0 ; firstUpper < len; ) {
                char c = value[firstUpper];
                if ((c >= Character.MIN_HIGH_SURROGATE)
                        && (c <= Character.MAX_HIGH_SURROGATE)) {
                    int supplChar = codePointAt(firstUpper);
                    if (supplChar != Character.toLowerCase(supplChar)) {
                        break scan;
                    }
                    firstUpper += Character.charCount(supplChar);
                } else {
                    if (c != Character.toLowerCase(c)) {
                        break scan;
                    }
                    firstUpper++;
                }
            }
            return this;
        }

        char[] result = new char[len];
        int resultOffset = 0;  /* result may grow, so i+resultOffset
                                * is the write location in result */

        /* Just copy the first few lowerCase characters. */
        System.arraycopy(value, 0, result, 0, firstUpper);

        String lang = locale.getLanguage();
        boolean localeDependent =
                (lang == "tr" || lang == "az" || lang == "lt");
        char[] lowerCharArray;
        int lowerChar;
        int srcChar;
        int srcCount;
        for (int i = firstUpper; i < len; i += srcCount) {
            srcChar = (int)value[i];
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
                    && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
                srcChar = codePointAt(i);
                srcCount = Character.charCount(srcChar);
            } else {
                srcCount = 1;
            }
            if (localeDependent ||
                srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
                srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
            } else {
                lowerChar = Character.toLowerCase(srcChar);
            }
            if ((lowerChar == Character.ERROR)
                    || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (lowerChar == Character.ERROR) {
                    lowerCharArray =
                            ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
                } else if (srcCount == 2) {
                    resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
                    continue;
                } else {
                    lowerCharArray = Character.toChars(lowerChar);
                }

                /* Grow result if needed */
                int mapLen = lowerCharArray.length;
                if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
                    result = result2;
                }
                for (int x = 0; x < mapLen; ++x) {
                    result[i + resultOffset + x] = lowerCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i + resultOffset] = (char)lowerChar;
            }
        }
        return new String(result, 0, len + resultOffset);
    }

String toLowerCase(Locale locale)该方法是将字符串中所有的大写字母转为小写字母,源码感觉有点复杂,我只能说一下我看懂的地方,它首先判断Locale对象是否为空,如果非空则进行下面的操作,它会首先有一个带标签的for循环,来检查是否存在一些字符需要被改变,判断了字符对应的unicode值然后过滤了所有的小写字母,只统计了非小写的字符个数。(后面就没有怎么看懂)。我们通常是会调用无参的方法,源码如下:

 public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }
public String toUpperCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }

        int firstLower;
        final int len = value.length;

        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstLower = 0 ; firstLower < len; ) {
                int c = (int)value[firstLower];
                int srcCount;
                if ((c >= Character.MIN_HIGH_SURROGATE)
                        && (c <= Character.MAX_HIGH_SURROGATE)) {
                    c = codePointAt(firstLower);
                    srcCount = Character.charCount(c);
                } else {
                    srcCount = 1;
                }
                int upperCaseChar = Character.toUpperCaseEx(c);
                if ((upperCaseChar == Character.ERROR)
                        || (c != upperCaseChar)) {
                    break scan;
                }
                firstLower += srcCount;
            }
            return this;
        }

        /* result may grow, so i+resultOffset is the write location in result */
        int resultOffset = 0;
        char[] result = new char[len]; /* may grow */

        /* Just copy the first few upperCase characters. */
        System.arraycopy(value, 0, result, 0, firstLower);

        String lang = locale.getLanguage();
        boolean localeDependent =
                (lang == "tr" || lang == "az" || lang == "lt");
        char[] upperCharArray;
        int upperChar;
        int srcChar;
        int srcCount;
        for (int i = firstLower; i < len; i += srcCount) {
            srcChar = (int)value[i];
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
                (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
                srcChar = codePointAt(i);
                srcCount = Character.charCount(srcChar);
            } else {
                srcCount = 1;
            }
            if (localeDependent) {
                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
            } else {
                upperChar = Character.toUpperCaseEx(srcChar);
            }
            if ((upperChar == Character.ERROR)
                    || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (upperChar == Character.ERROR) {
                    if (localeDependent) {
                        upperCharArray =
                                ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
                    } else {
                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
                    }
                } else if (srcCount == 2) {
                    resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
                    continue;
                } else {
                    upperCharArray = Character.toChars(upperChar);
                }

                /* Grow result if needed */
                int mapLen = upperCharArray.length;
                if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
                    result = result2;
                }
                for (int x = 0; x < mapLen; ++x) {
                    result[i + resultOffset + x] = upperCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i + resultOffset] = (char)upperChar;
            }
        }
        return new String(result, 0, len + resultOffset);
    }

这个是将字母转为大写的方法源码,我们通常也调用无参的形式:

public String toUpperCase() {
        return toUpperCase(Locale.getDefault());
    }
public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value;    /* avoid getfield opcode */

        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

String trim()对于非NULL对象String可以调用该方法,用来去除字符串中首尾空格,第一个循环是判断字符串的前面有几个空格,第二个循环是判断原字符串长度减去字符串后面的几个空格的长度,分别用两个变量来标记,最后只需要截取该字符起始索引和长度就可以了。我当时有个需求是只需要去掉字符串最后的空格,所以我读了该源码,进行了改造,可以参考我这篇博文Java去掉字符串的末尾空格当然可以实现只去掉字符串的首部空格,源码如下:

public String trimFirst(char[] value) {
        int len = value.length;
        int st = 0;
        char[] val = value;
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        return ((st > 0) || (len < value.length)) ? new String(val).substring(st, len) : new String(val);
    }

一个关于去掉空格的demo示例;

public class TestString {
    public static  void main(String[] args){
        String str = " abc de fg ";
        //abc de fg
        System.out.println(str.trim());
        //9
        System.out.println(str.trim().length());
        //abc de fg 
        System.out.println(TestString.trimFirst(str.toCharArray()));
        //10
        System.out.println(TestString.trimFirst(str.toCharArray()).length());
    }

    public static String trimFirst(char[] value) {
        int len = value.length;
        int st = 0;
        char[] val = value;
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        return ((st > 0) || (len < value.length)) ? new String(val).substring(st, len) : new String(val);
    }
}

public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
    }

char[] toCharArray()将一个字符串转为字符数组。

 public static String format(String format, Object... args) {
        return new Formatter().format(format, args).toString();
    }

static String format(String format, Object... args)该方法是用来格式化的,是一个静态方法,返回值为String类型,第一个参数是格式化的形式,后面是一个可变参数列表,下面是一个demo示例:

public class TestString {
    public static  void main(String[] args){
        String str = "GeeksforGeeks.";

        String gfg1 = String.format("My Company name is %s", str);
        String str2 = String.format("My answer is %.8f", 47.65734);
        String str3 = String.format("My answer is %15.8f", 47.65734);
        //My Company name is GeeksforGeeks.
        System.out.println(gfg1);
        //My answer is 47.65734000
        System.out.println(str2);
        //My answer is     47.65734000
        System.out.println(str3);
    }
}
public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

static String valueOf(Object obj)该方法是将对象转为字符串,是一个静态的方法,参数是一个对象object,返回值类型是String类型,注意:如果该Object对象为NULL,调用该方法就会报NULLPointException异常,所以调用此方法时应该需要做非NULL判断。


到这里为止String类的源码应该算是看完了,我觉得看源码的同时可以学习他的实现思路,来丰富自己的思路,同时还可以了解该类下面有什么方法,这些方法是用来做什么的,这样在开发中才可以选取恰当的方法来实现。

猜你喜欢

转载自blog.csdn.net/u012934325/article/details/83865997
今日推荐