學習String的第一步就是建立(聲明)字符串,咱們在這裏之因此分爲建立和聲明(實際上是一個意思,都是建立字符串,但二者卻有本質的區別)是由於String是一個很特殊的類,它的對象產生在五種建立對象以外,還有另一種方式,下面咱們就來詳細瞭解一下.html
Java沒有內置的字符串類型,而是在標準Java類庫中提供了一個預約義的不可改變(final)的類,很天然的叫作String。在Java語言中字符串必須包含在一對」」雙引號中.例如:「23.3」,」adc」,」ad%-」,」1+3」.」你好,安靜」,這些都是字符串常量(這裏所說的常量並不是是final的,不可更改的,而是可改變的,這裏的改變也並不是是改變字符串內容,而是改變String變量的指向),字符串常量是系統可以顯示的任何文字信息,甚至是單個字符。在這裏咱們必須再強調一下凡是被雙引號「」包含的都是字符串,不能做爲其它數據類型使用,若要使用須要轉型(可能出現類型轉換異常),如上「1+2」若是輸出的話是不會輸出3的,輸出結果是1+2.java
能夠經過一下語法格式來聲明字符串:面試
String str = [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 }
經過這種聲明的方式建立的字符串對象會首先到字符串常量池中去尋找是否存在這樣一個字符串,若是有那麼直接返回該字符串的地址,不然會在字符串常量池中建立該字符串而後使String變量指向該字符串。數組
字符串除了能夠直接賦值外,還能夠由另外一種方式來建立,下面咱們來介紹一下.函數
在Java中將字符串做爲對象來管理,所以能夠像建立其它類對象同樣來建立字符串對象。建立對象要用到構造方法。String類的經常使用構造方法以下:學習
String()
初始化新建立的 String
對象,使其表示空字符序列。ui
String(char a[],int offset,int length) 提取字符數組的一部分建立一個字符串對象.參數offset表示開始截取字符串的位置,length表示截取字符串的長度.this
String(char[] value) 該構造方法可分配一個新的String對象,使其表示字符數組參數中全部的元素鏈接的結果。spa
String(byte[] bytes)
經過使用平臺的默認字符集解碼指定的字節數組來構造新的 String
。3d
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); }
上面咱們分別針對兩種字符串的聲明進行了分析,下面咱們在來看一段代碼,而後進行內存分析:
//兩種字符串建立的對比 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.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)
分配一個新的字符串,其中包含當前包含在字符串構建器參數中的字符序列。字符串中關於空串和null串,是很容易弄混的一個地方,在這裏特意說一下:
空串「」是長度爲0的字符串。空串是一個Java對象,有本身的長度(0)和內容(空)。不過String變量還能夠存放一個特殊的值,名爲null,這表示目前沒有任何對象與該變量關聯,null也並不是是String特有的,它是一個關鍵字,屬於Java。要檢查一個字符串是否爲null,能夠經過(string == null)判斷。非空判斷也是程序中咱們常見的操做,咱們經過下面代碼來實現;
if(str != null && str.length() != 0)
關於空串,咱們就講解到這裏;