1. 程式人生 > >Notes 20180310 : String第二講_String的聲明與創建

Notes 20180310 : String第二講_String的聲明與創建

語言 -- 比較 文字 com link html 返回值 public

1 字符串的聲明與創建

  學習String的第一步就是創建(聲明)字符串,我們在這裏之所以分為創建和聲明是因為String是一個很特殊的類,它的對象產生在五種創建對象之外,還有另外一種方式,下面我們就來詳細了解一下.

1.1 聲明字符串

  在Java語言中字符串必須包含在一對””雙引號中.例如:“23.3”,”adc”,”ad%-”,”1+3”.”你好,安靜”,這些都是字符串常量,字符串常量是系統能夠顯示的任何文字信息,甚至是單個字符。在這裏我們必須再強調一下凡是被雙引號“”包含的都是字符串,不能作為其它數據類型使用,若要使用需要轉型(可能出現類型轉換異常),如上“1+2”如果輸出的話是不會輸出3的,輸出結果是1+2.

  可以通過一下語法格式來聲明字符串:

String str = [null];
  • String:描述符,指定該變量為字符串變量;
  • str:任意有效的標識符,表示字符串變量的名稱;
  • =:賦值運算符,在數學上我們可以理解為等號,在內存層面我們可以理解為將str指向一個內存地址;
  • Null:在這裏表示賦值的內容,如果未賦值,默認是初始化為null.否則表明聲明的字符串值為null.註意:成員字段可以不初始化,虛擬機給予初始化,局部變量必須進行初始化.
package cn.stringPractise.create;    
//字符串創建的兩種方法--聲明字符串
    public
static void test1(){ String str1 = "abc"; String str2 = null; // String str3;如果沒有初始化就是用,會提示未曾初始化錯誤 //System.out.println(str3);//The local variable str3 may not have been initialized System.out.println("str1:"+str1+"--hashcode:"+str1.hashCode()); System.out.println(str2);
//獲取hashcode,此時null根本沒有分配內存,自然是一個空指針,下面會報出空指針異常 // System.out.println("str2:"+str2+"--hashcode:"+str2.hashCode()); java.lang.NullPointerException }

技術分享圖片

1.2 創建字符串

  字符串除了可以直接賦值外,還可以由另一種方式來創建,下面我們來介紹一下.

  在Java中將字符串作為對象來管理,因此可以像創建其它類對象一樣來創建字符串對象。創建對象要用到構造方法。String類的常用構造方法如下:

String() 初始化新創建的 String對象,使其表示空字符序列。

String(char a[],int offset,int length) 提取字符數組的一部分創建一個字符串對象.參數offset表示開始截取字符串的位置,length表示截取字符串的長度.

String(char[] value) 該構造方法可分配一個新的String對象,使其表示字符數組參數中所有的元素連接的結果。

String(byte[] bytes) 通過使用平臺的默認字符集解碼指定的字節數組來構造新的 String

String(byte[] bytes, Charset charset)  構造一個新的String由指定用指定的字節的數組解碼charset 。 String(byte[] bytes, int offset, int length)  通過使用平臺的默認字符集解碼指定的字節子陣列來構造新的 String String(byte[] bytes, int offset, int length, Charset charset)  構造一個新的String通過使用指定的指定字節子陣列解碼charset
String(byte[] bytes, int offset, int length, String charsetName)  構造一個新的 String通過使用指定的字符集解碼指定的字節子陣列。

  除了上面幾種使用String類的構造方法來創建字符串變量外,還可通過字符串常量的引用賦值給一個字符串變量,以及提供的其它構造方法等(關於構造函數,我們在本節的最後會簡單總結一下)。

【例7.1.2.1】驗證創建字符串的幾種方式。

//字符串創建的第二種方法--創建字符串
    public static void test2(){
        char[] ch = {‘花‘,‘褪‘,‘殘‘,‘紅‘,‘青‘,‘杏‘,‘小‘}; 
        //使用字符數組創建字符串對象
        String str1 = new String(ch);
        System.out.println(str1);
        //提取字符數組中的一部分,創建愛你字符串對象
        String str2 = new String(ch, 1, 3);
        System.out.println(str2);
        String str3 = str1;
        System.out.println(str3);
        System.out.println(str1 == str3);
    }

技術分享圖片

1.3 兩種字符串創建的對比

  上面我們分別針對兩種字符串的聲明進行了分析,下面我們在來看一段代碼,然後進行內存分析:

    //兩種字符串創建的對比
    public static void test3(){
        String str1 = "123";
        String str2 = new String("123");
        String str3 = new String("234");
        String str4 = "234";
        System.out.println("str1:"+str1+"--hashcode:"+str1.hashCode());
        System.out.println("str2:"+str2+"--hashcode:"+str2.hashCode());
        System.out.println("str3:"+str3+"--hashcode:"+str3.hashCode());
        System.out.println("str4:"+str4+"--hashcode:"+str4.hashCode());
        String str5 = new String("123");
        System.out.println("str5:"+str5+"--hashcode:"+str5.hashCode());
        System.out.println((str2 == str5)+":"+(str1 == str2));
        System.out.println((str2.equals(str5))+":"+(str1.equals(str2)));
    }

技術分享圖片

  通過上面的比對,我們明白了一個問題,那就是hashcode一般情況下作為真實的內存地址的映射,我們知道String中”==”比較的是地址的內存地址,而equals()的源碼如下:

public boolean equals(Object anObject) {
        if (this == anObject) {//此時通過對象地址判斷,地址一樣自然是同一個對象
            return true;
        }
        if (anObject instanceof String) {//判斷該對象是否是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重寫了Object的equals(),通過比對hashcode和字符串內容來確定equals的返回值,當他們有一點滿足true就是true.下面我們來分析一下上面的test3()在內存中的情形:

技術分享圖片

  美術功底太差,將就看吧,從上面我們可以看出,通過聲明字符串的形式進行字符串的創建的時候,會先在字符串常量池中查看是否有這個字符串,如果有那麽就將這個引用指向這個字符串的地址,如果沒有那麽就在字符串常量池中創建該字符串,並將指針指向該字符串的內存地址.

  而通過new創建字符串則不同,它會在堆中創建一個字符串對象,然後才是在字符串常量池中查找是否有這個字符串,如果有那麽會在堆中的對象中放入一個該字符串的地址,如果沒有在字符串常量池中創建字符串並將地址放在堆中對象裏邊,而我們的指針是指向堆中的字符串對象的.有了這個分析,我們思考一道面試題有關字符串常量池和String.intern;

1.4 String的構造方法簡略

  在1.2創建字符串中,我們簡單了解了幾種String的構造方法,本節我們將String的構造方法羅列出來,我們可以作為一個消遣內容,紅色的為個人認為重要的構造方法,藍色的是棄用的無需關註.

  1. String() 初始化新創建的 String對象,使其表示空字符序列。
  2. String(byte[] bytes) 通過使用平臺的默認字符集解碼指定的字節數組來構造新的 String
  3. String(byte[] bytes, Charset charset)構造一個新的String由指定用指定的字節的數組解碼charset 。
  4. String(byte[] ascii, int hibyte) 已棄用  此方法無法將字節正確轉換為字符。 從JDK 1.1開始,首選的方法是通過String構造函數獲取Charset ,字符集名稱,或者使用平臺的默認字符集。
  5. String(byte[] bytes, int offset, int length)通過使用平臺的默認字符集解碼指定的字節子陣列來構造新的 String
  6. String(byte[] bytes, int offset, int length, Charset charset)構造一個新的String通過使用指定的指定字節子陣列解碼charset 。
  7. String(byte[] ascii, int hibyte, int offset, int count)已棄用此方法無法將字節正確轉換為字符。 從JDK 1.1開始,首選的方式是通過String構造函數獲取Charset ,字符集名稱,或使用平臺的默認字符集。
  8. String(byte[] bytes, int offset, int length, String charsetName)構造一個新的 String通過使用指定的字符集解碼指定的字節子陣列。
  9. String(byte[] bytes, String charsetName)構造一個新的String由指定用指定的字節的數組解碼charset 。
  10. String(char[] value)分配一個新的 String ,以便它表示當前包含在字符數組參數中的字符序列。
  11. String(char[] value, int offset, int count)分配一個新的 String ,其中包含字符數組參數的子陣列中的字符。
  12. String(int[] codePoints, int offset 起始位置, int count)分配一個新的 String ,其中包含 Unicode code point數組參數的子陣列中的 字符 。
  13. String(String original)初始化新創建的String對象,使其表示與參數相同的字符序列; 換句話說,新創建的字符串是參數字符串的副本。
  14. String(StringBuffer buffer)分配一個新的字符串,其中包含當前包含在字符串緩沖區參數中的字符序列。
  15. String(StringBuilder builder) 分配一個新的字符串,其中包含當前包含在字符串構建器參數中的字符序列。

Notes 20180310 : String第二講_String的聲明與創建