JDK中String类的源码分析(二)

1、startsWith(String prefix, int toffset)方法

包括startsWith(*),endsWith(*)方法,都是调用上述一个方法

 1     public boolean startsWith(String prefix, int toffset) {
 2         char ta[] = value;
 3         int to = toffset;
 4         char pa[] = prefix.value;
 5         int po = 0;
 6         int pc = prefix.value.length;
 7         // Note: toffset might be near -1>>>1.
 8         if ((toffset < 0) || (toffset > value.length - pc)) {
 9             return false;
10         }
11         while (--pc >= 0) {
12             if (ta[to++] != pa[po++]) {
13                 return false;
14             }
15         }
16         return true;
17     }

上述算法的时间复杂度,最差的情况下为O(n)(取决于匹配子串的长度),最理想的情况下为O(1);

2、indexOf方法

有多个重载的方法,参数可以为字符,也可以为字符串

 1     static int indexOf(char[] source, int sourceOffset, int sourceCount,
 2             char[] target, int targetOffset, int targetCount,
 3             int fromIndex) {
 4         if (fromIndex >= sourceCount) {
 5             return (targetCount == 0 ? sourceCount : -1);
 6         }
 7         if (fromIndex < 0) {
 8             fromIndex = 0;
 9         }
10         if (targetCount == 0) {
11             return fromIndex;
12         }
13 
14         char first = target[targetOffset];
15         int max = sourceOffset + (sourceCount - targetCount);
16 
17         for (int i = sourceOffset + fromIndex; i <= max; i++) {
18             /* Look for first character. */
19             if (source[i] != first) {
20                 while (++i <= max && source[i] != first);
21             }
22 
23             /* Found first character, now look at the rest of v2 */
24             if (i <= max) {
25                 int j = i + 1;
26                 int end = j + targetCount - 1;
27                 for (int k = targetOffset + 1; j < end && source[j]
28                         == target[k]; j++, k++);
29 
30                 if (j == end) {
31                     /* Found whole string. */
32                     return i - sourceOffset;
33                 }
34             }
35         }
36         return -1;
37     }

这个匹配子串的方法比较复杂,值得深入研究

3、substring方法

在JDK1.7之前的代码中,substring存在严重内存泄露问题,然而,这个问题在JDK1.7之后的版本中都有了改善;

因为JDK1.7中修改了构造方法,调用Arrays.copyOfRange()方法,只是复制出数组的一部分;

关于String类的构造方法,可以参看: JDK中String类的源码分析(一)

4、concat方法

连接两个字符串

 1     public String concat(String str) {
 2         int otherLen = str.length();
 3         if (otherLen == 0) {
 4             return this;
 5         }
 6         int len = value.length;
 7         char buf[] = Arrays.copyOf(value, len + otherLen);
 8         str.getChars(buf, len);
 9         return new String(buf, true);
10     }

5、split方法,切割字符串

 1     public String[] split(String regex, int limit) {
 2         
 3         char ch = 0;
 4         if (((regex.value.length == 1 &&
 5              ".$|()[{^?*+\".indexOf(ch = regex.charAt(0)) == -1) ||
 6              (regex.length() == 2 &&
 7               regex.charAt(0) == '\' &&
 8               (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
 9               ((ch-'a')|('z'-ch)) < 0 &&
10               ((ch-'A')|('Z'-ch)) < 0)) &&
11             (ch < Character.MIN_HIGH_SURROGATE ||
12              ch > Character.MAX_LOW_SURROGATE))
13         {
14             int off = 0;
15             int next = 0;
16             boolean limited = limit > 0;
17             ArrayList<String> list = new ArrayList<>();
18             while ((next = indexOf(ch, off)) != -1) {
19                 if (!limited || list.size() < limit - 1) {
20                     list.add(substring(off, next));
21                     off = next + 1;
22                 } else {    // last one
23                     //assert (list.size() == limit - 1);
24                     list.add(substring(off, value.length));
25                     off = value.length;
26                     break;
27                 }
28             }
29             // If no match was found, return this
30             if (off == 0)
31                 return new String[]{this};
32 
33             // Add remaining segment
34             if (!limited || list.size() < limit)
35                 list.add(substring(off, value.length));
36 
37             // Construct result
38             int resultSize = list.size();
39             if (limit == 0)
40                 while (resultSize > 0 && list.get(resultSize - 1).length() == 0)
41                     resultSize--;
42             String[] result = new String[resultSize];
43             return list.subList(0, resultSize).toArray(result);
44         }
45         return Pattern.compile(regex).split(this, limit);
46     }

6、trim方法,去除字符串两端的空格

 1     public String trim() {
 2         int len = value.length;
 3         int st = 0;
 4         char[] val = value;    /* avoid getfield opcode */
 5 
 6         while ((st < len) && (val[st] <= ' ')) {
 7             st++;
 8         }
 9         while ((st < len) && (val[len - 1] <= ' ')) {
10             len--;
11         }
12         return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
13     }

算法时间复杂度在O(log(n))左右,截取,创建一个新的字符串;

总结:

在String类中的大多数方法,都存在new对象的操作,因为String的不可变性,如果大量的调用这些方法,在内存中会产生大量的String对象;

这样对GC的压力很非常大,很可能会出现内存溢出;

原文地址:https://www.cnblogs.com/lianliang/p/5737705.html