1. 程式人生 > >Java| String s=new String("abc")和Stirng s = "abc"的區別

Java| String s=new String("abc")和Stirng s = "abc"的區別

本文希望能弄懂的問題: String s=new String(“abc”)和String s = "abc"的區別?

思考: 在Java中,我們是如何建立一個類的例項的? 在我們常用的建立一個類的例項(物件)的方法有以下兩種: 一、使用new建立物件。 二、呼叫Class類的newInstance方法,利用反射機制建立物件。

一.使用""建立String物件的規則(String s1 = “yveshe”)

先來一到面試題,看看輸出結果是什麼:

String s1 = "yveshe";
String s2 = "yveshe";

System.out.println(s1 == s2)
; System.out.println(s1 == "yveshe"); System.out.println("Hello Yves" == "Hello Yves");

輸出結果如下:

true
true
true

通過前提介紹我們知道建立已給類的例項(物件)有兩種方法:通過new關鍵字建立物件,或者使用反射機制建立類的例項物件.顯然在String s1 = "yveshe";產生String類的例項不包括在其中,這就是一種特的產生String類例項物件的方式.那麼它的規則到底是怎樣的呢? String s1 = "yveshe";,這行程式碼被執行的時候,JAVA虛擬機器首先在字串池中查詢是否已經存在了值為"yveshe"的這麼一個物件,它的判斷依據是String類equals(Object obj)方法的返回值。如果有,則不再建立新的物件,直接返回已存在物件的引用;如果沒有,則先建立這個物件,該放在了字串池中,再將它的引用返回。

在執行String s2 = "yveshe";其實字串"yveshe"已經在常量池中存在,所以並不會建立新的物件而是將原來字面量"yveshe"的引用地址返回了.

**總結: ** 使用""建立的String物件的方式,首先會在常量池中查詢是否已經存在字串字面量,存在返回已經存在字串的引用,否則先建立這個物件,該物件存放在String Pool中,然後將他的引用返回.

二使用new關鍵字建立String物件的規則(String s= new String(“YvesHe”))

我們先來看一到面試題,如下程式碼建立了幾個物件?

String s= new String("YvesHe")
;

答案是建立了2個物件,一個是字面量"YvesHe"建立的String物件,在String Pool中,一個是new操作產生的String物件,存放在Java Heap中. (這裡假定了StringPool中在程式碼執行之前不存在"YvesHe",否則則只會建立一個由於new操作產生的String物件,原理分析可以看第一大點)

分析如下: 我們可以把上面這行程式碼分成String s、=、"YvesHe"和new String()四部分來看待。 String s只是定義了一個名為s的String型別的變數,因此它並沒有建立物件; =是對變數s進行初始化,將某個物件的引用(或者叫控制代碼)賦值給它,顯然也沒有建立物件; 最後的new String(“abc”)又能被看成"abc"和new String();

不理解的new String(“abc”)又能被看成"abc"和new String();需要思考下如下程式碼:

String s= new String("YvesHe");

String tmp = "YvesHe";
String s= new String(tmp);

總結: new 關鍵字一定會建立一個新的物件,存放在Java Heap中.

三.使用+操作符號建立的String物件

示例一:

String s1 = "yves" + "he";
System.out.println(s1 == "yveshe"); 

輸出結果:

true

反編譯程式碼如下:

String s1 = "yveshe";
System.out.println(s1 == "yveshe");

分析: String s1 = "yves" + "he";在編譯期常量摺疊成String s1 = "yveshe";所以輸出結果為true.

示例二:

String s1 = "yves";
String s2 = s1 + "he";
System.out.println(s2 == "yveshe");

輸出結果:

false

反編譯程式碼如下:

String s1 = "yves";
String s2 = (new StringBuilder(String.valueOf(s1))).append("he").toString();
System.out.println(s2 == "yveshe");

從反編譯的程式碼結果,我們可以知道s2的String例項物件的產生形式是使用的StringBuilder的toString方法底層是使用String的public String(char value[], int offset, int count)構造方法,這裡產生的物件並不會放在String Pool中.所以上面輸出結果為false.如果列印語句修改為System.out.println(s2.intern() == "yveshe");,則會列印true.

四.String s = new String("YvesHe").intern();中intern方法到底作用何在?

String s = new String("YvesHe").intern();
System.out.println(s == "YvesHe");

輸入結果:

true

分析: 1.首先建立一個字面量為"YvesHe"的String物件,存放在String Pool中. (假定執行該程式碼之前String Pool中無字面量"YvesHe"存在) 2.然後通過String的構造方法new String(String original)來產生一個新的String物件,存放在JavaHeap中,構造引數為字面量"YvesHe"在String Pool的引用 3.通過在JavaHeap上建立的String例項呼叫它的intern方法來獲得String Pool中"YvesHe"的引用 等價如下:

String stringPoolRef = "YvesHe";
String javaHeapRef = new String(stringPoolRef);
String stringPoolRefSame = javaHeapRef.intern();
System.out.println(stringPoolRef == stringPoolRefSame);

到此,我們都沒有發現intern的方法的正真作用,反倒是覺得很多餘,因為無論是我們通過 String s = “YvesHe”; 還是String s = new (“YvesHe”);其實本質都會在String pool中生成了一個字面量為"YvesHe"的物件,接下來我們看下以下程式碼的執行結果

String s1 = "yves";
String s2 = "he";
String s3 = s1 + s2;

System.out.println(s3 == "yveshe");

輸出結果:

false

我們先反編譯一下以上程式碼:

String s1 = "yves";
String s2 = "he";
String s3 = (new StringBuilder(String.valueOf(s1))).append(s2).toString();
System.out.println(s3 == "yveshe");

從反編譯的程式碼結果,我們可以知道s3的String例項物件的產生形式是使用的StringBuilder的toString方法底層是使用String的public String(char value[], int offset, int count)構造方法,這裡產生的物件並不會放在String Pool中.所以上面輸出結果為false.如果列印語句修改為System.out.println(s3.intern() == "yveshe");,則會列印true.

總結: intern()方法有兩個作用,第一個是將字串字面量放入常量池(如果池沒有的話),第二個是返回這個常量的引用。