格智教育對String的對象乾貨分享

格智教育對String的對象乾貨分享

一共創建了多少String的對象?[我開始的答案:5個.jf,new,3jf,3jf3,3jf34]

首先看JLS的有關論述:

一,字元串轉換的環境[JLS 5.4 String Conversion]

字元串轉換環境僅僅指使用雙元的+運算符的情況,其中一個操作數是一個String對象.在這一特定情形下,另一操作數轉換成String,表達式的結果是這兩個String的串接.

二,串接運算符[JLS 15.18.1 String Concatenation Operator + ]

如果一個操作數/表達式是String類型,則另一個操作數在運行時轉換成一個String對象,並兩者串接.此時,任何類型都可以轉換成String.[這裡,我漏掉了"3"和"4"]

如果是基本數據類型,則如同首先轉換成其包裝類對象,如int x視為轉換成Integer(x).

現在就全部統一到引用類型向String的轉換了.這種轉換如同[as if]調用該對象的無參數toString方法.[如果是null則轉換成"null"].因為toString方法在Object中定義,故所有的類都有該方法,而且Boolean, Character, Integer, Long, Float, Double, and String改寫了該方法.

關於+是串接還是加法,由操作數決定.1+2+str+3+4 就很容易知道是"3jf34".[BTW :在JLS的15.18.1.3中舉的一個jocular little example,真的很無趣.]

下面的例子測試了改寫toString方法的情況..

class A

{ int i = 10;

public static void main(String []args)

{ String str = new String("jf");

str += new A();

System.out.print(str);

}

public String toString(){ return " a.i ="+i+"
"; }

}

三,字元串轉換的優化

按照上述說法,str = 1+2+str+3+4;語句似乎應該就應該生成5個String對象:

1+2 =3,then 3→Integer(3)→"3" in pool? [假設如此]

"3"+str(in heap) = "3jf" (in heap)

"3jf" +3 ,first 3→Integer(3)→"3" in pool? [則不創建] then "3jf3"

"3jf3"+4 create "4" in pool

then "3jf34"

這裡我並不清楚3,4轉換成字元串後是否在池中,所以上述結果仍然是猜測.

為了減少創建中間過渡性的字元串對象,提高反覆進行串接運算時的性能,a Java compiler可以使用StringBuffer或者類似的技術,或者把轉換與串接合併成一步.例如:對於 a + b + c ,Java編譯器就可以將它視為[as if]

new StringBuffer().append(a).append(b).append(c).toString();

注意,對於基本類型和引用類型,在append(a)過程中仍然要先將參數轉換,從這個觀點看,str = 1+2+str+3+4;創建的字元串可能是"3","4"和"3jf34"[以及一個StringBuffer對象].

現在我仍然不知道怎麼回答str = 1+2+str+3+4;創建了多少String的對象,.或許,這個問題不需要過於研究,至少SCJP不會考它.

3,這又不同:str = "3"+"jf"+"3"+"4";

如果是一個完全由字元串文字組成的表達式,則在編譯時,已經被優化而不會在運行時創建中間字元串.測試代碼如下:

String str1 ="3jf34";

String str2 ="3"+"jf"+"3"+"4";

if(str1 == str2) { System.out.println("str1 == str2"); }

else { System.out.println("think again"); }

if(str2.equals(str1)) System.out.println("yet str2.equals(str1)");

可見,str1與str2指向同一個對象,這個對象在pool中.所有遵循Java Language Spec的編譯器都必須在編譯時對constant expressions 進行簡化.JLS規定:Strings computed by constant expressions (y15.28) are computed at compile time and then treated as if they were literals.

對於String str2 ="3"+"jf"+"3"+"4";我們說僅僅創建一個對象.注意,"創建多少對象"的討論是說運行時創建多少對象.

BTW:編譯時優化

String x = "aaa " + "bbb ";

if (false) { x = x + "ccc "; }

x += "ddd ";

等價於: String x = "aaa bbb "; x = x + "ddd ";

//這個地方我自己進行了編譯,不過和他的結論不一樣,好像當用x+="ddd"的時候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具體為什麼我也不清楚.

4,不變類

String對象是不可改變的(immutable).有人對str = 1+2+str+3+4;語句提出疑問,怎麼str的內容可以改變?其實仍然是因為不清楚:引用變數與對象的區別.str僅僅是引用變數,它的值??它持有的引用可以改變.你不停地創建新對象,我就不斷地改變指向.[參考TIJ的Read-only classes.]

不變類的關鍵是,對於對象的所有操作都不可能改變原來的對象[只要需要,就返回一個改變了的新對象].這就保證了對象不可改變.為什麼要將一個類設計成不變類?有一個OOD設計的原則:Law of Demeter.其廣義解讀是:使用不變類.只要有可能,類應當設計為不變類.


推薦閱讀:

教育的最終結果是讓每個人都有自己獨特的模樣
深度解析—研學教育借政策之勢如何破壁
書單推薦 | 應用這些技巧,讓你的課堂活躍又高效
凝心聚力 以賽促教——渭南軌道交通運輸學校教育教學續新篇
牽引力教育重新詮釋「優秀四有新青年」

TAG:大學教育 | 教育 | 學校教育 |