Java源碼之String

在String的源碼上有這麼一段註釋:
Strings are constant; their values cannot be changed after they
are created. String buffers support mutable strings.
Because String objects are immutable they can be shared.
字符串是常量,在創建後,它們的值是不能改變的。字符串緩衝區支持可變字符串,因爲字符串對象是不變的它們可以共享(即StringBuffer)。
String str = “abc”;等價於:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

一、String的定義

//在Java中String類其實就是對字符數組的封裝
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    //定義的主要變量:
    /** The value is used for character storage. */
    private final char value[];//常量,在構造器中初始化
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    //默認構造函數,使用此構造函數是不必要的,因爲字符串是不可變的。
    public String() {
        this.value = new char[0];
    }
    //新建的字符串是original的副本,如非必要,這個構造函數是不必要的,因爲字符串是不可變的。
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
    //char數組的值拷貝到當前char數組中,char數組的變化不會影響新建的字符串。
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    //這裏還有幾個byte數組轉字符串的構造函數沒有列出

    //StringBuffer裏面的字符串也是已char[] value的形式存儲的,只不過StringBuffer是線程安全
    //的,需要加
   public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }
}

二、String的常用方法

1、獲取字符串相關信息的操作

//字符串的長度,即char[]的長度
 public int length() {
     return value.length;
 }
 public boolean isEmpty() {
    return value.length == 0;
 }

//返回指定位置的char值
 public char charAt(int index) {
      if ((index < 0) || (index >= value.length)) {
          throw new StringIndexOutOfBoundsException(index);
      }
      return value[index];
  }
  //通過特定的charset把當前字符串轉變成char數組
 public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
     if (charsetName == null) throw new NullPointerException();
      return StringCoding.encode(charsetName, value, 0, value.length);
 }

//與特定的對象比較,該對象不爲空並且是一個字符串,具有相同的字符序列,則返回true。
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;
  }
//字符串忽略大小寫的的比較,首先看兩個字符串的引用是否是同一個,如果不是的話就對字符串的char數組進行對比,相等就繼續比較,不等先轉成大寫的char值比較,不然再轉車些小的char值比較。
 public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
 }


//從字符串的char數組的toffset位置開始,與prefix比較,如果個數等於prefix.length()的char值與
//prefix的char值相等,則字符串是從 toffset以prefix爲開頭的字符串
 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) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
   }
 public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
 }
 public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
 }

//s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 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;
  }

//返回指定字符的在該字符串中的第一個位置的索引
// ch   a character (Unicode code point)
public int indexOf(int ch) {
   return indexOf(ch, 0);//正序遍歷查找
}
//返回指定字符的在該字符串中的最後一個位置的索引
public int lastIndexOf(int ch) {
    return lastIndexOf(ch, value.length - 1);//倒序遍歷查找
}


public int indexOf(String str) {
       return indexOf(str, 0);
}

public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
}

2、字符串的增刪改操作

上面的是一些獲取信息的基本操作,下面的操作源代碼則反映了string的不可變性:

 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);
 }
  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);
 }
//將指定的字符串拼接在當前字符串之後,先把當前字符串的char數組copy到新的char數組buf中,在使用
//getChars方法把str的char數組添加到buf中,最後生成一個新的string並返回。
 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);
 }

    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;
                }
            }
            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;
    }

不僅在這幾個方法,包括toUpperCase、toLowerCase、trim等方法都是自己本身或者調用的方法先對char數組進行操作,操作完成後生成一個新的String對象並返回。
小結:

1、String引用的的char數組value是一個private final定義的變量,我們沒有權限改變這個數組的內容(反射機制是可以操作這個value引用的值的,但是除非腦子有病纔會這麼做吧),也不能改變這個char數組的引用(final的特性,參考final關鍵字)。

2、字符串的增刪改等改變操作,都是自己本身或者調用的方法先對char數組進行操作,操作完成後生成一個新的String對象並返回。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章