String引用資料型別
一、String類的第一種方式 (原文地址:https://blog.csdn.net/wangdajiao/article/details/52087302)
1、直接賦值
例:String str = "hello";
直接賦值實際上就是相當於一個匿名物件(“hello”)設定了一個名字(str),String類的匿名物件是由系統自動生成,不在由使用者自己建立,產生了匿名物件就一定在堆記憶體在開闢了一塊堆記憶體空間,並且由一塊棧記憶體指向這塊堆記憶體
2、採用直接賦值的String類物件的記憶體地址完全相同,stra,strb,strc指向同一塊記憶體地址
例:
publicclass StringDemo { public static void main(String[] args) { String stra = "hello" ; String strb = "hello" ; String strc = "hello" ; System.out.println(stra == strb);//true System.out.println(stra == strc);//true System.out.println(strb == strc);//true } }
原因:
共享設計模式:在JVM底層實際上會有一個物件池(不一定儲存String物件),當代碼之中使用了直接賦值的方式定義了一個String類物件時,會將此字串物件所使用的匿名物件入池儲存,而如果後續還有其他String類物件也採用直接賦值方式,並且設定了同樣的內容的時候,將不會開闢新的堆記憶體空間,而是使用已有的物件進行引用的分配,從而繼續使用。(integer同樣如此)
--如下:
Integer是int的封裝物件,兩個物件==比較的是棧的值
Integer a = new Integer(1);
Integer b = new Integer(1);
a與b存的是Integer的堆中的地址,而不是值
a、b指向堆中的地址顯然不同所以 a==b 為false
int c = 1; int為值型別,
因為int在堆中是不開闢記憶體的,他在棧中的值則為他本身的值
所以a==c比較的是他們各自的value, a==c為true
Integer e=1; 這個比較特殊,直接賦值 它有獨立的記憶體,每次賦值時將檢查記憶體中是否有值跟他匹配的,若有則把此記憶體地址付給e,若沒有,開闢新的記憶體
你可以嘗試下面的例子:
Integer t = 1;
Integer t1 = 1;
t==t1 為true,如上所說,此時t與t1指向的是同一塊記憶體
new 一定是開闢新的記憶體,直接賦值則不一定開闢新的記憶體
因為a的引用指向堆,而e指向專門存放他的記憶體,所以他們的記憶體地址不一樣
所以a==e為false
c==e等同於 a==c,一個引用型別一個值型別
二、String類的第二種方式
1、構造方法
例:String str = new String("hello")
構造方法一定要使用關鍵字new,一旦使用了關鍵字new就表示要開闢新的堆記憶體空間,如果使用的是構造方法的方式產生String類物件,實際上開闢了兩塊堆記憶體空間(其中匿名物件產生記憶體空間將成為垃圾空間)
public class StringDemo { public static void main(String[] args) { String stra = new String("hello"); String strb = "hello"; System.out.println(stra == strb);//false } }
除了記憶體浪費以外,如果使用了構造方法產生String類物件,其內容不會儲存在物件池之中。因為是使用了關鍵字new開闢的新記憶體
2、手動入池:使用String類定義的public String intern();
public class StringDemo { public static void main(String[] args) { //使用了構造方法建立物件,而後手動入池 String stra = new String("hello").intern(); String strb = "hello"; System.out.println(stra == strb);//ture } }
總結 :
String類兩種例項化的區別
1、直接賦值:只會開闢一塊堆記憶體空間,並且會自動儲存在物件池之中,以供下次重複使用
2、構造方法:會開闢兩塊堆記憶體空間,其中有一塊空間將成為垃圾,並且不會自動入池,但是使用者可以使用intern()自動入池
在實際工作中,使用直接賦值產生String類物件
三、字串一旦定義則不可改變
例:
public class StringDemo { public static void main(String[] args) { String str = "Hello"; str = str + "World"; str += "!!!"; System.out.println(str); } }
記憶體分析圖:
因此,字串的內容實際上沒有改變,而對於字串物件內容的改變,是利用了引用關係的變化而實現的,但是每一次的改變都會產生垃圾空間,因此String的內容不要過多頻繁的修改