## HashSet 1. jdk1.7之前,使用數組加鏈表的方式實現 2. jdk1.8之後,在鏈表長度大於8並且數組長度超過32的情況下,會轉成紅黑樹結構 3. HashSet的本質是一個HashMap,它所有的value都是一致的,傳入的參數作為key,因此HashSet中不允許重覆數據 4. ...
引用傳遞和值傳遞,從上學那會兒就開始強調的概念,不管你是電腦相關專業還是自學Java,一定聽過這麼一句話:
方法調用參數如果是對象,那就是引用傳遞,如果是基本數據類型,就是值傳遞。
比如:function(Object o)就是引用傳遞,function(int i)就是值傳遞。這兩個概念似乎很好理解,我們只需要記住對象和基本數據類型的區別就行了。但是,真的是這樣嗎?
有一段代碼如下:
public static void main(String[] args) { int i = 0; System.out.println(i); change(i); System.out.println(i); } private static void change(int i) { i = 1; }
輸出結果比較好猜測,也應該都能答對:
0 0
下一個問題,如果將int改成String呢?
public static void main(String[] args) { String s = "0"; System.out.println(s); change(s); System.out.println(s); } private static void change(String s) { s = "1"; }
輸出的結果如下:
0 0
嗯?有疑問了吧?不是引用傳遞嗎?我在方法里命名修改了s的值,為什麼輸出還是”0“呢?難度String作為Object有什麼特殊性?
別急,繼續看下一段代碼:
public static void main(String[] args) { Person p = new Person("0"); System.out.println(p); change(p); System.out.println(p); } private static void change(Person p) { p = new Person("1"); } static class Person{ String name; public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } }
結果會輸出什麼?
Person{name='0'}
Person{name='0'}
看來String和其他Object沒什麼不同,可是這樣的結果好像不太符合我們對引用傳遞的認知啊。其實我感覺這兩個概念沒有必要區分,實質是一回事,都是將棧中引用複製了一份傳遞到方法中,無論在方法中如何對引用操作,都是操作的副本,只是對於基本數據類型來說,值存儲在棧中,引用存儲的就是值,而對象來說,引用中存儲的是對象在堆中的記憶體地址,參數傳遞時生成的副本仍然指向了原來引用指向的對象,所以如果直接操作該對象是有效的。簡單畫個圖方便理解:
如果對p的操作不是將該引用指向一個新的值,而是對p指向的對象進行操作,就能看到所謂引用傳遞的效果了例如:
public static void main(String[] args) { Person p = new Person("0"); System.out.println(p); change(p); System.out.println(p); } private static void change(Person p) { p.name = "1"; } static class Person{ String name; public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } }
此時,執行結果為:
Person{name='0'}
Person{name='1'}
總結:
Java進行方法調用時參數傳遞是將棧中的引用複製了一份到該方法的工作區,如果引用指向了一個堆中的對象,那麼副本也指向這個對象。