1.不可变性string的不可变主要体现在三个方面:
string类被定义为final类型,不可被继承
string中的value[]被定义为final
string中的所有生成新的string的操作底层都调用array.copy或者system.copy来生成一个新的string对象
2.构造函数,string的构造函数较为简单,但以下几个较为特殊 public string(string original) { this.value = original.value; this.hash = original.hash; } string(char[] value, boolean share) { // assert share : unshared not supported; this.value = value; }
以上两个是较为特殊的一类构造函数,第一个用一个现成的string来初始化一个新的string对象,构造方法直接将新的string对象的value指向老的value对象。由于string是不可变的,所以这里不需要重新copy一份value的对象。第二个构造方法看似会破坏string类型的不可变性(当参数value变化时string也会变化),但该构造方法并没有声明为public,只允许在包内使用,被声明为public的string(char value[])底层调用的是array.copy来实现底层数据拷贝的,上述的两个构造函数已经不建议使用
public string(char value[], int offset, int count) { if (offset < 0) { throw new stringindexoutofboundsexception(offset); } if (count < 0) { throw new stringindexoutofboundsexception(count); } // note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new stringindexoutofboundsexception(offset + count); } this.value = arrays.copyofrange(value, offset, offset+count); }
上面这个构造函数较为典型,很多其他的构造函数都与其类似或者底层调用了该构造函数,入参是一个char数组(byte[]),offset偏移位置及count偏移量。底层调用arrays.copy函数来进行深度复制。
public string(stringbuffer buffer) { synchronized(buffer) { //保证线程安全 this.value = arrays.copyof(buffer.getvalue(), buffer.length()); } } public string(stringbuilder builder) { this.value = arrays.copyof(builder.getvalue(), builder.length()); }
上述两个构造函数入参分别是stringbuffer和stringbuilder,底层都是调用arrays.copyof,唯一不同的是stringbuffer是线程安全的,所有调用时需要用synchronized关键字。
3.其他方法 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; } 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; } }
indexof和lastindexof主要是index和lastindex函数的底层调用,通读代码会发现底层实现并没有特别牛逼的kmp算法,仍然是一个字符一个字符扫描实现的。其中lastindexof还是用了continue startsearchforlastchar;相对来说比较少见。
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; } } //如果找不到则返回this 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++; } //返回新的string,利用上述包内的非public构造函数 return new string(buf, true); } } return this; }
replace用于将string对象中的一个字符替换为另一个字符,如果找不到制定的字符则返回本身,如果找到则会另建一个新的string对象返回。
---恢复内容结束---
以上就是string源码的实例解读的详细内容。
