java String部分源碼解析


String類型的成員變量

/** String的屬性值 */  
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    /**數組被使用的開始位置**/
    private final int offset;

    /** The count is the number of characters in the String. */
    /**String中元素的個數**/
    private final int count;

    /** Cache the hash code for the string */
   /**String類型的hash值**/
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

   有上面的成員變量可以知道String類的值是final類型的,不能被改變的,所以只要一個值改變就會生成一個新的String類型對象,存儲String數據也不一定從數組的第0個元素開始的,而是從offset所指的元素開始。

如下面的代碼是生成了一個新的對象,最后的到的是一個新的值為“bbaa”的新的String的值。

     String a = new String("bb");
     String b = new String("aa");
     String c =  a + b;    

 

  也可以說String類型的對象是長度不可變的,String拼接字符串每次都要生成一個新的對象,所以拼接字符串的效率肯定沒有可變長度的StringBuffer和StringBuilder快。

 

然而下面這種情況卻是很快的拼接兩個字符串的:

    String a = "aa" + "bb";

  原因是:java對它字符串拼接進行了小小的優化,他是直接把“aa”和“bb”直接拼接成了“aabb”,然后把值賦給了a,只需生成一次String對象,比上面那種方式減少了2次生成String,效率明顯要高很多。

 


 

下面我們來看看String的幾個常見的構造方法

 

1、無參數的構造方法:

public String() {
    this.offset = 0;
    this.count = 0;
    this.value = new char[0];
    }

 

 

2、傳入一個Sring類型對象的構造方法

public String(String original) {
    int size = original.count;
    char[] originalValue = original.value;
    char[] v;
      if (originalValue.length > size) {
         // The array representing the String is bigger than the new
         // String itself.  Perhaps this constructor is being called
         // in order to trim the baggage, so make a copy of the array.
            int off = original.offset;
            v = Arrays.copyOfRange(originalValue, off, off+size);
     } else {
         // The array representing the String is the same
         // size as the String, so no point in making a copy.
        v = originalValue;
     }
    this.offset = 0;
    this.count = size;
    this.value = v;
    }

 

 

 3、傳入一個字符數組的構造函數

public String(char value[]) {
    int size = value.length;
    this.offset = 0;
    this.count = size;
    this.value = Arrays.copyOf(value, size);
    }

 

 

4、傳入一個字符串數字,和開始元素,元素個數的構造函數

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.offset = 0;
        this.count = count;
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

 

   由上面的幾個常見的構造函數可以看出,我們在生成一個String對象的時候必須對該對象的offset、count、value三個屬性進行賦值,這樣我們才能獲得一個完成的String類型。

 


 

常見函數:

 

1、判斷兩個字符串是否相等的函數(Equal):其實就是首先判斷比較的實例是否是String類型數據,不是則返回False,是則比較他們每一個字符元素是否相同,如果都相同則返回True,否則返回False

public boolean equals(Object anObject) {
 if (this == anObject) {
     return true;
 }
 if (anObject instanceof String) {
     String anotherString = (String)anObject;
     int n = count;
     if (n == anotherString.count) {
  char v1[] = value;
  char v2[] = anotherString.value;
  int i = offset;
  int j = anotherString.offset;
  while (n-- != 0) {
      if (v1[i++] != v2[j++])
   return false;
  }
  return true;
     }
 }
 return false;
    }

 

 

 2、比較兩個字符串大小的函數(compareTo):輸入是兩個字符串,返回的0代表兩個字符串值相同,返回小於0則是第一個字符串的值小於第二個字符串的值,大於0則表示第一個字符串的值大於第二個字符串的值。

  比較的過程主要如下:從兩個字符串的第一個元素開始比較,實際比較的是兩個char的ACII碼,加入有不同的值,就返回第一個不同值的差值,否則返回0

public int compareTo(String anotherString) {
 int len1 = count;
 int len2 = anotherString.count;
 int n = Math.min(len1, len2);
 char v1[] = value;
 char v2[] = anotherString.value;
 int i = offset;
 int j = anotherString.offset;

 if (i == j) {
     int k = i;
     int lim = n + i;
     while (k < lim) {
  char c1 = v1[k];
  char c2 = v2[k];
  if (c1 != c2) {
      return c1 - c2;
  }
  k++;
     }
 } else {
     while (n-- != 0) {
  char c1 = v1[i++];
  char c2 = v2[j++];
  if (c1 != c2) {
      return c1 - c2;
  }
     }
 }
 return len1 - len2;
    }
View Code

 

 

 3、判斷一個字符串是否以prefix字符串開頭,toffset是相同的長度

public boolean startsWith(String prefix, int toffset) {
 char ta[] = value;
 int to = offset + toffset;
 char pa[] = prefix.value;
 int po = prefix.offset;
 int pc = prefix.count;
 // Note: toffset might be near -1>>>1.
 if ((toffset < 0) || (toffset > count - pc)) {
     return false;
 }
 while (--pc >= 0) {
     if (ta[to++] != pa[po++]) {
         return false;
     }
 }
 return true;
    }

 public int hashCode() {
 int h = hash;
 if (h == 0) {
     int off = offset;
     char val[] = value;
     int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }

 

 

 4、連接兩個字符串(concat)

public String concat(String str) {
 int otherLen = str.length();
 if (otherLen == 0) {
     return this;
 }
 char buf[] = new char[count + otherLen];
 getChars(0, count, buf, 0);
 str.getChars(0, otherLen, buf, count);
 return new String(0, count + otherLen, buf);
    }

 

 

 連接字符串的幾種方式

1、最直接,直接用+連接

     String a = new String("bb");
     String b = new String("aa");
     String c =  a + b;

 

 

 2、使用concat(String)方法

      String a = new String("bb");
      String b = new String("aa"); 
      String d = a.concat(b);

 

 

3、使用StringBuilder

 String a = new String("bb");
 String b = new String("aa");
     
StringBuffer buffer = new StringBuffer().append(a).append(b);

 

   第一二中用得比較多,但效率比較差,使用StringBuilder拼接的效率較高。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM