String类源码分析 -- by maxwell
今天把String类的源码看了一遍,该类大概2000多行代码,注释就有1000多行。这个类主要都是对char[]的操作。
我大概注释了60%左右的方法,重要的方法做了分析注释,对这些方法也算有了比较深刻的认识。
//返回一个新的字符串,它是此字符串的一个子字符串。该子字符串从指定索引处的字符开始,直到此字符串末尾。 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); //直接调用String的构造方法创建子串 }
//返回一个新字符串,它是此字符串的一个子字符串。 //该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。 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); //和上面的方法一样,也是直接调用String的构造方法创建子串 }
//将指定字符串连接到此字符串的结尾。 //实际上是调用Arrays.copyOf()处理的,而Arrays.copyOf()又是调用System.arraycopy()实现的。 public String concat(String str) { int otherLen = str.length(); //指定字符串str的长度 if (otherLen == 0) { //如果指定字符串长度为0,直接返回原字符串 return this; } int len = value.length; //原字符串长度 char buf[] = Arrays.copyOf(value, len + otherLen); //创建一个新的字符数组,长度为两字符串长度之和,将原字符串先拷贝到里面 str.getChars(buf, len); //再从第len位开始将str拷贝到该字符数组中 return new String(buf, true); }
//通过用 newChar 替换此字符串中出现的所有 oldChar 得到的一个新的字符串。 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 == oldChar) { //在原字符串中找到要替换的字符 break; //此时i就是该字符第一次出现的位置 } } if (i < len) { char buf[] = new char[len]; //新建一个长度为len的字符数组 for (int j = 0; j < i; j++) { //从索引0开始到i-1的字符拷贝到新的字符数组中 buf[j] = val[j]; } while (i < len) { //处理从i到len位置的字符,这里是个很巧妙的办法! char c = val; buf = (c == oldChar) ? newChar : c; //如果是oldChar,则替换为newChar,如果不是则不改变 i++; } return new String(buf, true); //构造新的字符串 } } return this; }
//告知此字符串是否匹配给定的正则表达式。 //这个方法直接调用了Pattern.matches()方法,跟踪到最后发现调用了Matcher类的构造方法 public boolean matches(String regex) { return Pattern.matches(regex, this); }
//当前字符串是否包含了指定的 char 值序列。 //该方法只能判断是否包含,而indexOf()方法既能判断是否包含,还能返回第一次出现的位置。 //实际上,该方法就是调用了indexOf()方法来实现的!indexOf()如果不存在返回-1。 public boolean contains(CharSequence s) { return indexOf(s.toString()) > -1; //这里使用大于而不是等于是个好的习惯! }
//使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 //与正则有关的方法 public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); }
//根据匹配给定的正则表达式来拆分此字符串。注意返回的是String[]的数组! //limit 参数控制模式应用的次数,因此影响所得数组的长度。 //这个方法写得很牛逼! 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 && //如果正则表达式长度为1,并且第一个字符不是元字符 ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || (regex.length() == 2 && //如果正则表达式长度为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<>(); //这里居然用了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); }
//根据给定正则表达式的匹配拆分此字符串。 //实际上就是调用上面的方法 public String[] split(String regex) { return split(regex, 0); }
|