1. 程式人生 > >java.lang(String)

java.lang(String)

每次 訪問 pat abc 文件路徑 .net copy itl near

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

    /** The value is used for character storage. */
    private final char value[];

    private int hash; // Default to 0

    public String() { //無參構造器
        this.value = new char[0];
    }

    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

/*****傳入一個字符數組的構造函數,使用java.utils包中的Arrays類復制******/
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

/*******傳入一個字符串數字,和開始元素,元素個數的構造函數******/
    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.value = Arrays.copyOfRange(value, offset, offset+count);
    }
/*********************類似方法不介紹了**************************/

    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

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

/***********s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*********/
    public int hashCode() {
        int h = hash;
/***如果hash沒有被計算過,並且字符串不為空,則進行hashCode計算*****/
        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;
    }    
/***intern方法是Native調用,它的作用是在方法區中的常量池裏通過equals方法尋找等值的對象,如果沒有找到則在常量池中
開辟一片空間存放字符串並返回該對應String的引用,否則直接返回常量池中已存在String對象的引用。*****/ public native String intern();

舉例:

String a = "abc";
String b = new String("ab1").intern();
if ( a == b ) {
  System.out.println("a == b");  
} else {
  System.out.println("a不等於b");
}
打印出:a == b

1. 什麽是不可變類

所謂不可變類,就是創建該類的實例後,該實例的屬性是不可改變的,Java提供的包裝類和java.lang.String類都是不可變類。當創建它們的實例後,其實例的屬性是不可改變的。

需要註意的是,對於如下代碼

String s="abc";
s="def";

你可能會感到疑惑,不是說String是不可變類嗎,這怎麽可以改變呢,平常我也是這樣用的啊。請註意,s是字符串對象的”abc”引用,即引用是可以變化的,跟對象實例的屬性變化沒有什麽關系,這點請註意區分。

2.String類被設計成不可變的原因

  1. 字符串常量池的需要
  2. 允許String對象緩存HashCode

    Java中String對象的哈希碼被頻繁地使用, 比如在hashMap 等容器中。

    字符串不變性保證了hash碼的唯一性,因此可以放心地進行緩存.這也是一種性能優化手段,意味著不必每次都去計算新的哈希碼.

  3. 安全性:String被許多的Java類(庫)用來當做參數,例如 網絡連接地址URL,文件路徑path,還有反射機制所需要的String參數等, 假若String不是固定不變的,將會引起各種安全隱患。

  4. 線程安全:因為字符串是不可變的,所以是多線程安全的,同一個字符串實例可以被多個線程共享。這樣便不用因為線程安全問題而使用同步。字符串自己便是線程安全的。

3. 如何實現一個不可變類

既然不可變類有這麽多優勢,那麽我們借鑒String類的設計,自己實現一個不可變類。
不可變類的設計通常要遵循以下幾個原則:

    1. 將類聲明為final,所以它不能被繼承。
    2. 將所有的成員聲明為私有的,這樣就不允許直接訪問這些成員。
    3. 對變量不要提供setter方法。
    4. 將所有可變的成員聲明為final,這樣只能對它們賦值一次。
    5. 通過構造器初始化所有成員,進行深拷貝(deep copy)。
    6. 在getter方法中,不要直接返回對象本身,而是克隆對象,並返回對象的拷貝。

java.lang(String)