String中方法的源码整理

837 阅读2分钟

String

String在Java中实际上是以字符数组的方式进行存储的,并且通过源码可以看出。

char val[] = value;

在String中每次调用都是将它的value重新复制给另一个新的字符数组,所以我们不能更改它原本的值,而且value也不能被子类继承,所以String是不可更改的。

有一种情况String的值可以进行修改【反射】。后面在说

String类中的属性

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
	//字符数组,存储字符串的值
	private final char value[];
	//字符串类型的hash值,默认是0;
	private int hash;
    //String类的序列化ID,通过ID来识别软件版本
    private static final long serialVersionUID = -6849794470754667710L;
    
    private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
    
}
/*
*StringBuffer:线程安全的带缓存的String,可变的字符串
*/
String str = "abc";	//创建了一个对象

String str1 = new String("def");//创建了两个对象

str1 = str1 + str;//创建了一个"abcdef"字符串对象,底层使用了StringBuffer的append();

//String str = "abc";
char data[] = {'a','b','c'};
String str == new String(data);

构造函数

/*无参构造*/
//不能进行追加,删除等操作,只能进行覆盖操作
public String(){
	this.value = "".value;
}

//将参数的value和hash值都直接赋值给新创建的对象
public String (String original){
    this.value = original.value;
    this.hash = original.hash;
}

//截取字符串的子串,substring就是调用此构造函数
public String(char value[]/*截取字符串的字符数组*/, int offset/*开始的位置*/, int count/*截取的长度*/){
    if(offset < 0){
        throws new StringIndexOutOfBoundsException(offset);
    }
    if(count <= 0){
        //截取长度不能小于0
        if(count < 0){
            throws new StringIndexOutOfBoundsException(count);
        }
        //count == 0时就代表没有进行截取,返回传入的value值
        if(offset <= value.length){
            this.value = "".value;
            return;
        }
    }
    //如果offset超届抛出异常
    if(offset > value.length - count){
        throws new StringIndexOutOfBoundsException(offset+count);
    }
    //都没有问题的时候
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

String类的方法

hashCode

获取字符串的hash码

//String中的hashCode
//在String中进行重写
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;
}

//Object中的hashCode
//看不见具体的实现方法,它自动给你返回一个hash值
public native int hashCode();

equals

字符串进行比较,看是否相等

//Object中的equals
public boolean equals(Object obj){
    return (this == obj)	//比较内存值
}

//String中的equals
public boolean equals(Object anObject){
    if(this == anObject){
        return true;
    }
    //测试anObject是否是String的实例
    if(anObject instanceof String){
        //将anObject强制转换成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;
}

charAt

获取想要位置的字符

public char charAt(int index){
	if((index < 0) || (index >= value.length)){
		//索引位置超出界限,抛出异常
		throw new StringIndexOutOfBoudsException(index);
	}
	//返回索引位置的字符
	return value[index];
}

substring

剪下一段字符串

public String substring(int beginIndex){
	if(beginIndex < 0){
        //超出界限异常
        throw new StringIndexOutOfBoudsException(beginIndex);
    }
    //剪切的长度
    int subLen = value.length - beginIndex;
    //剪切的长度不能超过字符串的长度
    if(subLen < 0){
        throws new StringIndexOutOfBoudsException(subLen);
    }
    //如果index从0开始就返回字符串全部,不然就新建一个字符串返回
    return (beginIndex == 0) ? this : new String(value,beginIndex,subLen);
}

indexOf

查找字符在字符串中的位置

public int indexOf(int ch/*传入字符时自动转化为int*/){
	return indexOf(int ch, int fromIndex/*开始查找的位置*/);
}
//进行重载
public int indexOf(int ch, int fromIndex){
	final int max = value.length;
    if(fromIndex < 0){
        //如果输入错误的index那么让函数从头开始查找
        fromIndex = 0;
    } else if(fromIndex >= max){
        //选择范围超出了界限
        return -1;
    }
    //查找通用字符,在java中存储的值通常都是小于MIN的
    //MIN_SUPPLEMENTARY_CODE_POINT = 0x010000
    if(ch < Character.MIN_SUPPLEMENTARY_CODE_POINT){
        final char[] value = this.value;
        for(int i = fromIndex; i < max; i ++){
            //找到后返回下标
            if(value[i] == ch){
                return i;
            }
        }
        //没有找到
        return -1;
    } else {
        //查找的是补充字符,不是通用字符
        return indexOfSupplementary(ch, fromIndex);
    }
}

replace

替换字符

public String replace(char oldChar, char newChar){
    //要进行替换的字符不能相同,相同的话就相当于没有替换
    if(oldChar != newChar){
        int len = value.length;
        int i = -1;//记录是否有需要替换的字符
        char[] val = value;//避免直接操作原字符串
        //遍历查看需要替换字符的位置
        while(++i < len){
            if(val[i] == oldChar){
                break;
            }
        }
        //进行替换
        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 ++;
            }
            //返回替换后的字符串对象
            return new String (buf, true);
        }
    }
    return this;
}

trim

去除字符串中两头的空格,在ASCII码中,空格是可见字符的最小值。

image-20210728145758913

public String trim(){
	int len = value.length;
    int st = 0;//字符串的开始位置
    char[] val = value;
    //找到可见字符的起始位置
    while((st < len) && (val[st] <= ' ')){
        //遇见不可见字符则起始位置向后加
        st ++;
    }
    //找到可见字符的结束位置
    while((st < len) && val[len - 1] <= ' '){
        //遇见不可见字符则结尾向前加
        len --;
    }
    //将字符串从st开始到len结束进行剪切
    return ((st > 0) || (len < value.length))/*最少有一个空格被解决*/ ? substring(st,len) : this/*没有空格被消除*/;
}

split

按照给定的规则将字符串分割成数组

image-20210728152854156

image-20210728152937214

image-20210728152956631

image-20210728153014483

image-20210728153034596

public String[] split(String regex){
	return split(regex, 0);	//进行重载,从字符串头开始
}

public String[] split(String regex, int limit){
    char ch = 0;
    /*
    *regex为一个字符时,这个字符不能为正则的元字符,例如"^$.+\\?{}[]"等
    *regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母
    */
    if(((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)/*regex为一个字符时,这个字符不能为正则的元字符*/ ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&/*regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母*/
            (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<>();
        
        while((next = indexOf(ch, off)) != -1/*查询regex在String中的位置,确认String中有regex的存在,等于this.indexOf(ch, off)*/){
            if(!limited || list.size() < limit - 1){
                //没有进行次数初始化,或者当前数组的大小小于规定的次数
                //将不包含regex的子字符串放入数组中
                list.add(substring(off,next));
                //off直接到已经查到的regex位置加1,跳过现在的regex
                off = next + 1;
            } else {
                //现在数组的大小已经等于limit - 1,只需要进行最后一次操作
                list.add(substring(off, value.length));
                off = value.length;
                break;
            }
        }
        if(off == 0){
            //没有找到字符串中的regex
            return new String[]{this};
        }
        if(!limited || list.size() < limit){
            //传入的limit > 字符串中regex的次数,需要将剩余的部分添加到数组中
            list.add(substring(off, value.length));
        }
        //构造结果
        int resultSize = list.size();
        if(limit == 0){
            //没有传入参数或者传入的时0时,将list最后面的空数据删除掉
            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);
}

如果没有使用第51行的代码的话将会造成下面的这个结果

"boo:foo:boo".split("0",0)
-----------result--------------
{"b","",":f","",":b",""}