String可以说是我们最长用的一个类了,但是你真的理解她吗?废话不多说,直接开整。
public final class String
implements java.io.Serializable, Comparable, CharSequence
String类实现了三个接口,表明了她是可序列化,可比较的。并且实现了接口中一些字符
/** 用来存储字符,String底层维护的就是一个字符数组,findl修饰,不可变 */
private final char value[];
/** 缓存字符串的hashcode(散列码) */
private int hash; // Default to 0
/**
* 空参构造,初始化一个空串,一般没什么用
*/
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
/**
* 拷贝了一份新的数组
*/
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
//bytes数组offset位置开始,以charsetName的编码格式,拷贝length个字节到value数组中
public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException {
if (charsetName == null) throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
}
/**
* 重写了父类的equals方法
*/
public boolean equals(Object anObject) {
if (this == anObject) { //同一个对象返回true
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) { //长度相等
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) { //比较每个字符是否相等
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
/**
* 比较两个字符串,依次比较每个字符,如果返回正数 ,则当前字符串大于另一个字符串,反之,则小。如果其中一个字符串是另一个字符串的子串,那么更长的更大
*/
public int compareTo(String anotherString) {
int len1 = value.length; //当前字符串的长度
int len2 = anotherString.value.length; //要比较的字符串的长度
int lim = Math.min(len1, len2); //取两个长度的最小值
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) { //当k没有越界
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) { //如果两个字符不想等
return c1 - c2; //做减法
}
k++;
}
return len1 - len2;
}
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) { //在prefix长度范围内,从头开始依次比较字符是否相等
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
/**
* 返回字符串的hashCode值
* 算法:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* s[i]表示i位置的字符,n是字符串的长度,^表示幂运算
* 空串的hash值是0
*
*/
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;
}
/**
* 把指定的字符串连接到这个字符串的末尾。
* 如果参数字符串的长度是 0,直接返回该对象
* 否则链接两个对象
*/
public String concat(String str) {
int otherLen = str.length(); //获取指定字符串的长度
if (otherLen == 0) { //如果是0,直接返回
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
/**
* 替换
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode 在一个方法中需要大量引用实例域变量的时候,使用方法中的局部变量代替引用可以减少getfield操作的次数,提高性能。*/
//找到oldChar最开始出现的位置
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
//从这个位置开始
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) { //把i之前的字符拷贝到buf数组中
buf[j] = val[j];
}
while (i < len) { //i之后的位置进行判断,如果是oldChar则替换
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
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;
}
/**
* intern方法是Native调用,它的作用是在方法区中的常量池里通过equals方法寻找等值的对象,
* 如果没有找到则在常量池中开辟一片空间存放字符串并返回该对应String的引用,否则直接返回常量池中已存在String对象的引用。
*/
public native String intern();
split();
indexOf();