經過代碼說明 Java 引用傳遞在堆棧上的關係。java
能夠從JVM的內存空間存放上說明,值傳遞 和引用傳遞。
堆(線程共享):對象、對象的全局變量、數組
棧(線程私有):聲明爲局部變量的 基本數據類型、對象引用(是引用,不是對象自己)、方法參數數組
public class JavaParam { public Bean bean1 = new Bean("1"); public Bean bean2 = new Bean("1"); public String str1 = new String("str1"); public String str2 = new String("str1"); void setObjA(Bean bean) { bean = new Bean("a"); } void setObjB(Bean bean) { bean.setId("b"); } void setStrA(String str) { str = new String("strA"); } void setStrB(String str) { str.replace("str1", "strA"); // 或者 str = "strA"; // 或者 str = str.concat("strA") 原來的str都不會改變。 } public static void main(String[] args) { JavaParam javaParam = new JavaParam(); System.out.println(javaParam.bean1); // 1 System.out.println(javaParam.bean2); // 1 System.out.println(javaParam.str1); // str1 System.out.println(javaParam.str2); // str1 javaParam.setObjA(javaParam.bean1); javaParam.setObjB(javaParam.bean2); javaParam.setStrA(javaParam.str1); javaParam.setStrB(javaParam.str2); System.out.println(javaParam.bean1); // 1 System.out.println(javaParam.bean2); // b System.out.println(javaParam.str1); // str1 System.out.println(javaParam.str2); // str1 } }
針對 public Bean bean1 = new Bean("1"); 這句話會建立1個對象new Bean("1"),1個引用 bean1。
若是這句話在方法中,則 bean1在棧上,隨方法結束出棧而消失。
若是這句話在方法外,則 bean1在堆上。
顯然 bean1 、bean二、str一、str2 相關的對象和對象引用都在堆上。安全
以setObjA方法舉例。進入方法後,建立棧幀時,由於是方法參數,因此會建立 bean 這個引用(在棧上)
bean = new Bean("a");這句是對棧上的bean賦值,和外面的bean1沒有關係。只是在堆裏建了一個new Bean("a")。
隨方法結束出棧,bean的引用消失。剛建出來new Bean("a")由於失去全部的 「GC ROOT」 引用而等待垃圾回收。this
以setObjB方法舉例。進入方法後,建立棧幀時,由於是方法參數,因此會建立 bean 這個引用(在棧上)。(以上都和setObjA一致)
bean.setId("b");這句是對堆上的對象操做,即外面的成員變量new Bean("1");也正是由於堆是線程共享的,才引起的出了各類線程安全問題。
隨方法結束出棧,bean的引用消失。new Bean("1");此刻仍然被 bean2 引用,不會被垃圾回收。線程
另外舉例了String的操做。做爲final的對象,String對象並不可變。要改String類型的全局變量,請使用this.str1 = "XXX"對象