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的压力很非常大,很可能会出现内存溢出;