參考資料:網易雲網課地址 http://study.163.com/course/courseMain.htm?courseId=1455026 一、String類的兩種實例化方法 (1)直接賦值 以上代碼可以輸出str的值,說明str 已被實例化(未實例化會為null)。我們知道String類並不 ...
參考資料:網易雲網課地址
http://study.163.com/course/courseMain.htm?courseId=1455026
一、String類的兩種實例化方法
(1)直接賦值
public class Test { public static void main(String arg[]) { String str = "hello world"; System.out.println(str); } }
以上代碼可以輸出str的值,說明str 已被實例化(未實例化會為null)。我們知道String類並不是基本數據類型,然而以上代碼並沒有用new關鍵字開闢記憶體空間。
(2)利用構造方法實例化:
其實在String類裡面含有一個構造方法: public String(String str) 在構造裡面依然要接收一個本類對象。
public class Test { public static void main(String args[]) { String str = new String("Hello World"); System.out.println(str); } }
說明String類有兩種形式,大家主觀上應該會認為第二種更加的符合規範,因為一般認為類都需使用new關鍵字來實例化。但實際來說並不是這樣的,具體得往下看。
二、字元串的比較
基本數值都可用“==”判斷是否相等,String也可以用“==”進行比較
public class B { public static void main(String[] args) { String stra = "Hello"; String strb = new String("Hello"); String strc = strb;//引用傳遞 System.out.println(stra == strb); System.out.println(stra == strc); System.out.println(strb == strc); } }
輸出結果為:
false false true
記憶體圖分析如下:
“==”符號比較的時數據的地址數值,由圖可知,雖然三個變數內容相同,但是地址值並不相同。
如果真要比較地址所指向的內容,可以使用String類裡面提供的方法 public boolean equals;
public class B { public static void main(String[] args) { String stra = "Hello"; String strb = new String("Hello"); String strc = strb;//引用傳遞 System.out.println(stra.equals(strb)); System.out.println(stra.equals(strc)); System.out.println(strb.equals(strc)); } }
結果為
true true true
以上通過equals方法實現了內容的比較,故應當註意在比較字元串時應當使用此方法
一道題目:
請解釋在字元串相等的判斷中“==”與“equals”的區別?
(1)“==”時Java提供的關係運算符,主要功能是進行數值相等判斷,如果用在String對象上,表示的是地址數值的比較;
(2)“equals()”是有String提供的一個方法,此方法專門負責進行字元串內容的比較;
三、字元串常量就是String的匿名對象
實際上任何語言都沒有提供字元串這一概念,很多語言使用字元數組來描述。Java里也沒有字元串這一基本數據類型,而是通過String類的匿名對象來實現。
例:觀察字元串是匿名對象
public class B { public static void main(String[] args) { String stra = "Hello"; System.out.println("Hello".equals(stra)); } }
匿名對象能夠調用方法,故說明字元串為一個匿名對象
所謂的直接賦值相當於 將一個對象設置了一個名字,但唯一的區別是,String類的匿名對象是由系統自動生成的,並不是由用戶直接定義。
開發小技巧:
為了避免出現空指向異常,可將字元串寫在前面調用方法
String input = //由用戶輸入 input。equals("hello")
以上代碼input由用戶輸入賦值,如果用戶沒有輸入則為空,那麼就會出現空指向異常。
為了儘量避免這一情況發生,可將其倒置
String input = //由用戶輸入 “hello”.equals(input)
四、兩種實例化方式的區別
下麵探討String類兩種實例化方式的區別
1.直接賦值
直接賦值就是將一個字元串的匿名對象設置一個名字
String str = "Hello";
此時在記憶體中會開闢一塊堆記憶體,並且由一塊棧記憶體指向該堆記憶體
我們接著分析以下代碼:
public class Test { public static void main(String args[] ) { String stra = "hello" ; String strb = "hello" ; String strc = "hello" ; System.out.println(stra == strb) ; System.out.println(stra == strc) ; System.out.println(strb == strc) ; } }
結果為:
true true true
此時我們發現,三個比較值都為真,也就是說三個String對象地址值相等(即三個變數名stra,strb,strc指向同一堆記憶體,為同一個對象)。
要想解釋以上結果,需引入共用模式的概念:
在JVM的底層存在有一個對象池(不一定只保存String對象),如果用直接賦值的方式進行String對象的實例化,會將該實例化對象(字元串)入池保存,如果下次繼續使用直接複製方式聲明String對象,並且設置了同樣的內容(字元串值),那麼將直接進行引用,不會開闢新的堆記憶體空間。(所謂的對象池就是一個對象數組)。
2.構造方法
構造方法即使用new關鍵字
String str = new String("hello");
記憶體圖分析
可以發現,如果使用構造方法將會開闢兩塊堆記憶體空間,並且其中一塊堆記憶體空間將變成垃圾空間。另外還會對字元串共用產生問題。
public class Test { public static void main(String args[] ) { String stra = new String("hello") ; String strb = "hello" ; System.out.println(stra == strb) ; } }
結果為
false
如果使用了構造方法其內容並不會保存在記憶體池之中。
如果希望存入記憶體池,需手工使用intern()方法
public class Test { public static void main(String args[] ) { String stra = new String("hello") .intern(); String strb = "hello" ; System.out.println(stra == strb) ; } }
結果為
true
五、總結
String類對象兩種實例化方式的區別:
(1)直接賦值:只會開闢一塊堆記憶體空間,並且會自動保存在對象池中供下次使用;
(2)構造方法: 會開闢兩塊堆記憶體空間,一塊將稱為垃圾,並且將不會自動保存在對象池中,可以使用intern()方法手工入池。