Windows電腦,idea中。雙擊shift,輸入String,便可出來。java
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; .... }
從這部分源碼中,咱們就能夠很好的理解「1.1 String 的特性」中的內容了!!!字符串,字符串,就是字符構建起來的串。面試
public class StringTest { @Test public void test1() { // String name = "abc"; 字面量的定義方式 String name = "abc"; String des = "abc"; name = "hell world"; System.out.println("name:"+name);// hello world System.out.println("des:"+des);// abc } @Test public void test2() { final int a = 2; a = 3; // 編譯不經過 } }
第一個問題:爲何name = "hell world",編譯成功,並能運行,不是說「它們的值在建立以後不能更改」嗎?;而test2()中卻編譯失敗?數組
首先,String屬性引用類型,而int是基本類型。ide
引用類型變量存儲地址值,而a是一個指向int類型的引用,指向2這個字面值。所以final int 修飾的變量就變爲常量了,常量是不能修改其值的,因此test2()編譯失敗。oop
那麼怎麼理解String 底層存儲使用final修飾的char型數組,更改其值爲何編譯成功,並能運行?簡單的JVM走一波。圖一:this
從圖中咱們能夠看出:idea
圖二:code
從圖中咱們能夠看出:對象
@Test public void test3() { String s1="javaWeb"; String s2="javaWeb"; String s3 = new String("javaWeb"); String s4 = new String("javaWeb"); System.out.println(s1==s2); System.out.println(s1==s3); System.out.println(s1==s4); System.out.println(s3==s4); }
直觀判斷:blog
集合JVM判斷:
結合JVM圖形就能夠很清楚的明白到底爲何錯,爲何對了。
public class Person { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } }
@Test public void test4() { Person p1 = new Person("Tom", 12); Person p2 = new Person("Tom", 12); System.out.println(p1.name==p2.name);// true?false? }
顯然爲true,Tom存儲在字符串常量池中,有且僅有一份。故p1.name==p2.name必然爲true
再來:
@Test public void test4() { Person p1 = new Person("Tom", 12); Person p2 = new Person("Tom", 12); System.out.println(p1.name==p2.name); p2.name="cxk"; System.out.println(p1.name==p2.name);// true?false }
確定是false, p2.name="cxk";會先在字符串常量池中查找,沒有就在常量池中建一個, p2.name地址指向它便可。【字符串的不可變性】
String s = new String("abc");方式建立對象,在內存中建立了幾個對象?
答:2個。一個是堆空間中new結構,另外一個是char[ ]對應的常量池中的數據:」abc「;
來,搞一下這個。
public void test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop"; String s4 = "javaEE" + "hadoop"; String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3 == s4); System.out.println(s3 == s5); System.out.println(s3 == s6); System.out.println(s3 == s7); System.out.println(s5 == s6); System.out.println(s5 == s7); System.out.println(s6 == s7); String s8 = s6.intern(); System.out.println(s3 == s8); }
結論:
代碼一:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { str = "test ok"; System.out.println("======"+str); ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
輸出結果是多少?
解析:作這道題必須明白幾個知識點
分析:
代碼二:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { // 第二步: //對於方法中的str,因爲第一步的賦值操做,它的地址值和「String str = new String("good");」中的str同樣,內容都爲good。 //接下來方法中對它進行賦值操做「test ok」。 //因爲String類型的不可變性(看源碼類爲final修飾,數據存儲結構爲也爲final修飾的char型數組),不可修改。 //所以JVM執行'str ="test ok";'時會在字符串常量池中新建一個「test ok」而且更新方法中str的地址值。 //至此兩個str的地址值不一樣了,指向的內容也不一樣了。 能夠看「代碼三」中的對比結果。 str = "test ok"; // 第二步; //對於方法中的ch,因爲第一步的賦值操做,它的地址值和「char[] ch = {'t', 'e', 's', 't'};」中的ch同樣,內容都爲test。 //接下來,在方法中執行"ch[0] = 'b';" 數組中的第一個元素被賦值爲b。因爲是引用類型,此時類中成員變量char[] ch = {'t', 'e', 's', 't'};值也變爲best。 ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); // 第一步 // 傳遞的兩個實參,參數一,其實是把StringTest2類中成員變量str的地址值複製一份給StringTest2類中change方法中的形參變量str // 同理,StringTest2類中成員變量ch(數組:也是引用類型)的地址值複製一份給StringTest2類中change方法中的形參變量ch[] ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
代碼三:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { System.out.print("賦值以前兩個str的地址值比較爲:"); System.out.println(this.str==str); str = "test ok"; System.out.print("賦值以後兩個str的地址值比較爲:"); System.out.println(this.str==str); System.out.println("====================分割線========================"); ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
結果: