方法中的局部變量

直接上例子

1.方法中,局部變量爲基本類型

public class BaseChange {

	static void change(int a) {
		a += 5;
	}

	public static void main(String[] args) {
		int a = 1;
		change(a);
		System.out.println(a);
	}
}

得到的結果是 1。

2.方法中,局部變量爲數組

	static void changeArr(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			arr[i] += 100;
		}
	}

	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4 };
		changeArr(arr);
		System.out.println(Arrays.toString(arr));
	}

得到的結果是:

[101, 102, 103, 104]

3.方法中,局部變量爲String

	private static void change(String s) {
		s += "123";
	}

	public static void main(String[] args) {
		String s = "abc";
		change(s);
		System.out.println(s);
	}

得到的結果是:

abc

4.方法中,爲自定義對象

Foo

public class Foo {
	private int a;
	private int b;

	public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}

	public int getB() {
		return b;
	}

	public void setB(int b) {
		this.b = b;
	}

	@Override
	public String toString() {
		return "Foo [a=" + a + ", b=" + b + "]";
	}

}

測試類:

	static void changeFoo(Foo foo) {
		foo.setA(100);
		foo.setB(200);
	}

	public static void main(String[] args) {
		System.out.println("--change object-");
		Foo foo = new Foo();
		System.out.println(foo);
		changeFoo(foo);
		System.out.println(foo);
	}

得到的結果是:

--change object-
Foo [a=0, b=0]
Foo [a=100, b=200]


通過上面4個例子,可以得出以下結論:

1.當方法中的參數爲int等基本類型時候,方法結束,值不變;

2.當方法中參數爲String的時候,方法結束,值也不變;

3.當方法中參數爲對象(自定義對象和數組),方法技術,值發生了變化。


方法以棧幀的形式被虛擬機加載到虛擬棧裏面,每個線程單獨的管理自己的虛擬棧,所以,多個線程調用同一個方法,是相互不干擾的(前提不對全局的數據修改);

方法結束的時候,棧幀退出虛擬機棧。此時,所有的方法中的入參的聲明週期就結束了。


然後來回顧上面4段代碼:

第一段代碼:

1.當main中調用 int a=1的時候,基本變量a入虛擬棧

2.當調用方法change的時候,change方法棧幀入棧,局部變量a在棧幀上操作a+=5

3.當change方法結束的時候,棧幀退棧,打印a的值,a仍然是1。

因爲java中,基本類型就是存儲在虛擬棧中的。當然如果是全局變量,或者靜態變量,至少可以肯定的是,不是存儲在線程私有的虛擬棧上面的。


第二段代碼和第四段代碼

把他們放在一起講,是筆者粗糙的認爲,數組也是對象,所以直接放在一起解釋。對於對象,虛擬機棧中存儲的是該對象的應用,對象在堆上分配內存。

1.首先,方法進入前,變量引用入虛擬機棧,實際內容入堆,引用指向內容,且內容被初始化x:(當然,虛擬機實際的存儲模型裏面,還有一個類的信息,但是,數據確實是在堆裏修改的)


2.當調用change方法的時候,引用作爲參數傳輸到棧幀中,這時,兩個引用同時都指向對象,然後,方法中進行操作,綠色框框中的引用將對象的值改爲M

3.方法結束,棧幀退棧

因此,最後打印的結果,發生了變化,感覺是方法裏面把值修改了。


再來看第三段代碼:

我們先假設,String的值分配在堆上,但實際上(String有可能被分配在方法代,書上說的)。

String是一種特殊的對象,在堆上的表現是不可動態擴展的,就是如果 a="1"執行了a+="2"的操作,那麼,堆上會產生兩個String對象,一個是"1",一個是"2"。(java在編譯的過程中,高版本的或許會將a="1",a+="2"的這種代碼進行優化,不過,並不妨礙我們分析String作爲參數傳遞到方法中).

ok,現在來進行分析代碼:

1.首先String s="abc",此時,虛擬棧上會有一個s的變量引用,堆上有一個“abc”的對象,s的變量引用指向堆上的"abc"

2.調用change方法,棧幀入棧,參數棧,藍色的引用作爲參數傳遞給綠色的引用,這是,他們指向同一個對象:

3.方法中,執行s+="123",前面有說到,String比較特殊,他不會像其他對象一樣,在內部進行修改,而是新分配一塊內存。這是可以看到,方法中的引用和藍色的引用,已經指向的不是同一個對象了。

4.方法執行完畢,棧幀退棧:

所以,最終輸出的結果,仍然是"abc"。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章