Notes 20180310 : String第二講_String的聲明與創建
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; //字符串創建的兩種方法--聲明字符串 publicstatic 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
通過使用指定的指定字節子陣列解碼charsetString(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的構造方法羅列出來,我們可以作為一個消遣內容,紅色的為個人認為重要的構造方法,藍色的是棄用的無需關註.
String()
初始化新創建的String
對象,使其表示空字符序列。String(byte[] bytes)
通過使用平臺的默認字符集解碼指定的字節數組來構造新的String
。String(byte[] bytes, Charset charset)
構造一個新的String
由指定用指定的字節的數組解碼charset 。String(byte[] ascii, int hibyte)
已棄用 此方法無法將字節正確轉換為字符。 從JDK 1.1開始,首選的方法是通過String
構造函數獲取Charset
,字符集名稱,或者使用平臺的默認字符集。String(byte[] bytes, int offset, int length)
通過使用平臺的默認字符集解碼指定的字節子陣列來構造新的String
。String(byte[] bytes, int offset, int length, Charset charset)
構造一個新的String
通過使用指定的指定字節子陣列解碼charset 。String(byte[] ascii, int hibyte, int offset, int count)
已棄用此方法無法將字節正確轉換為字符。 從JDK 1.1開始,首選的方式是通過String
構造函數獲取Charset
,字符集名稱,或使用平臺的默認字符集。String(byte[] bytes, int offset, int length, String charsetName)
構造一個新的String
通過使用指定的字符集解碼指定的字節子陣列。String(byte[] bytes, String charsetName)
構造一個新的String
由指定用指定的字節的數組解碼charset 。String(char[] value)
分配一個新的String
,以便它表示當前包含在字符數組參數中的字符序列。String(char[] value, int offset, int count)
分配一個新的String
,其中包含字符數組參數的子陣列中的字符。String(int[] codePoints, int offset 起始位置, int count)
分配一個新的String
,其中包含 Unicode code point數組參數的子陣列中的 字符 。String(String original)
初始化新創建的String
對象,使其表示與參數相同的字符序列; 換句話說,新創建的字符串是參數字符串的副本。String(StringBuffer buffer)
分配一個新的字符串,其中包含當前包含在字符串緩沖區參數中的字符序列。String(StringBuilder builder)
分配一個新的字符串,其中包含當前包含在字符串構建器參數中的字符序列。
Notes 20180310 : String第二講_String的聲明與創建