天天看點

java源碼解析二、String類

二、String類

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {}
           

​ String是一個用final聲明的常量類,不能被任何類繼承且對象中的字元序列是不可變的。

​ String實作的接口

​ 1.Serializable接口:序列化辨別接口

​ 2.Comparable接口:用于比較兩個字元串的大小(按順序比較單個字元的ASCII碼)

​ 3.CharSequence接口:表示一個有序字元的集合

​ 字段屬性

//用來存儲屬性		
		private final char value[];
		//緩存字元串的哈希碼
		private int hash; // Default to 0
		//實作序列化的辨別
    	private static final long serialVersionUID = -6849794470754667710L;
           

​ String的構造方法

java源碼解析二、String類

​ String的方法

//String類重寫了equals方法,比較的是組成字元串的每個字元是否相同,如果相同則傳回true,否則傳回false
		public boolean equals(Object anObject) {
        	if (this == anObject) {
        	    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;
    	}

		/*
        String的hashCode算法公式:
        s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
        為什麼要選擇31作為乘積因子
		①、31是一個不大不小的質數,是作為 hashCode 乘子的優選質數之一。
		②、31可以被 JVM 優化,31 * i = (i << 5) - i。因為移位運算比乘法運作更快更省性能。*/
		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;
    	}

		//通過傳入的索引(數組下标),傳回指定索引的單個字元
	    public char charAt(int index) {
        	if ((index < 0) || (index >= value.length)) {
            	throw new StringIndexOutOfBoundsException(index);
        	}
        	return value[index];
    	}

		//按字母順序比較兩個字元串,是基于字元串中每個字元的 Unicode 值。當兩個字元串某個位置的字元不同時,傳回的是這一位置的字元 Unicode 值之差,當兩個字元串都相同時,傳回兩個字元串長度之差。
		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) {
            	char c1 = v1[k];
            	char c2 = v2[k];
            	if (c1 != c2) {
            	    return c1 - c2;
            	}
            	k++;
        	}
        	return len1 - len2;
    	}
		
		//在compareTo的基礎上忽略大小寫
		public int compareToIgnoreCase(String str) {
        	return CASE_INSENSITIVE_ORDER.compare(this, str);
    	}

		//将指定的字元串連接配接到此字元串的末尾
		public String concat(String str) {
        	int otherLen = str.length();
        	if (otherLen == 0) {
        	    return this;
        	}
        	int len = value.length;
        	char buf[] = Arrays.copyOf(value, len + otherLen);
        	str.getChars(buf, len);
        	return new String(buf, true);
    	}

		
		//參數ch是字元的Unicode值,傳回指定字元在字元串中第一次出現的索引
		public int indexOf(int ch) {
        	return indexOf(ch, 0);//從第一個字元開始搜尋
    	}

    	public int indexOf(int ch, int fromIndex) {
        	final int max = value.length;//字元的長度
        	if (fromIndex < 0) {		//指定索引的位置小于0,預設從0開始搜尋
        	    fromIndex = 0;
        	} else if (fromIndex >= max) {
        	    return -1;//索引值大于等于字元長度,直接傳回-1
        	}

        	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 {
                //當字元大于 65536時,處理的少數情況,該方法會首先判斷是否是有效字元,然後依次進行比較
        	    return indexOfSupplementary(ch, fromIndex);
        	}
    	}
	
		//内部調用  split(regex, 0) 方法
		public String[] split(String regex) {
        	return split(regex, 0);
    	}

		/*	①.limit>0,則pattern(模式)應用n - 1 次
			②.limit=0,則pattern(模式)應用無限次并且省略末尾的空字串
			③.limut<0,則pattern(模式)應用無限次
		*/
		public String[] split(String regex, int limit) {
			char ch = 0;
        	if (((regex.value.length == 1 &&
             	".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             	(regex.length() == 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;//大于0,limited==true,反之limited==false
            	ArrayList<String> list = new ArrayList<>();
            	while ((next = indexOf(ch, off)) != -1) {
                    //當參數limit<=0 或者 集合list的長度小于 limit-1
            	    if (!limited || list.size() < limit - 1) {
            	        list.add(substring(off, next));
            	        off = next + 1;
            	    } else { //判斷最後一個list.size() == limit - 1
            	    	list.add(substring(off, value.length));
                    	off = value.length;
                    	break;
                	}
            	}
                //如果沒有一個能比對的,傳回一個新的字元串,内容和原來的一樣
            	if (off == 0)
                	return new String[]{this};
				// 當 limit<=0時,limited==false,或者集合的長度小于limit時,截取添加剩下的字元串
            	if (!limited || list.size() < limit)
                	list.add(substring(off, value.length));
				//當limit==0時,如果末尾添加的元素為空(長度為0),則集合長度不斷減1,直到末尾不為空
            	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);
    	}	
		
		
		//将原字元串中所有的oldChar字元都替換為newChar字元,傳回一個
		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;
    	}
		
		//将比對正規表達式regex的比對項都替換成replacement字元串,傳回一個新的字元串。
    	public String replaceAll(String regex, String replacement) {
        	return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    	}

		//傳回一個索引beginIndex開始到結束的子字元串
		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);
    	}
		
		//傳回一個從索引 beginIndex 開始,到 endIndex 結尾的子字元串。
		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對象的intern()方法,如果常量池中有該對象了,直接傳回該字元串的引用(存在堆中就傳回堆中,存在池中就傳回池中),如果沒有,則将該對象添加到池中,并傳回池中的引用。
		public native String intern();
           

​ 常量池

Java運作時會維護一個String Pool(String池), 也叫“字元串緩沖區”。String池用來存放運作時中産生的各種字元串,并且池中的字元串的内容不重複。

​ String真的不可變嗎?

String str = "vae";
		//列印原字元串
		System.out.println(str);//vae
		//擷取String類中的value字段 
		Field fieldStr = String.class.getDeclaredField("value");
		//因為value是private聲明的,這裡修改其通路權限
		fieldStr.setAccessible(true);
		//擷取str對象上的value屬性的值
		char[] value = (char[]) fieldStr.get(str);
		//将第一個字元修改為 V(小寫改大寫)
		value[0] = 'V';
		//列印修改之後的字元串
		System.out.println(str);//Vae