Java——值傳遞和引用傳遞


值傳遞

在方法被調用時,實參通過形參把它的內容副本傳入方法內部,此時形參接收到的內容是實參值的一個拷貝,因此在方法內對形參的任何操作,都僅僅是對這個副本的操作,不影響原始值的內容。

 

先來看個例子:

public static void valueCross(int age,float weight) {
	System.out.println("傳入的age值:"+age);
	System.out.println("傳入的weight值:"+weight);
	age=23;
	weight=60;
	System.out.println("修改后的age值:"+age);
	System.out.println("修改后的weight值:"+weight);
}
	
	
public static void main(String[] args) {
	int age=10;
	int weight=50;
	valueCross(age,weight);
	System.out.println("方法執行后的age:"+age);
	System.out.println("方法執行后的weight:"+weight);
		
}

  

運行結果:

傳入的age值:10
傳入的weight值:50.0
修改后的age值:23
修改后的weight值:60.0
方法執行后的age:10
方法執行后的weight:50

  

我們可以看到valueCross方法執行后,實參age和weight的值並沒有發生變化,這是什么原因?

首先程序運行時,先從main方法開始執行,此時JVM為main()方法往虛擬機棧中壓入一個棧幀,即為當前棧幀,用來存放main()中的局部變量表(包括參數)、操作棧、方法出口等信息,如a和w都是mian()方法中的局部變量,因此可以斷定,age和weight是躺着mian方法所在的棧幀中

接着調用valueCross方法,此時JVM為valueCross()方法往虛擬機中壓入一個棧幀,即為當前棧幀,用於存放valueCross方法的局部變量等信息;因此age和weight是躺着valueCrossTest方法所在的棧幀中,而他們的值是從a和w的值copy了一份副本而得,如圖:

因此這兩個age和weight對應的內容不是同一個,在valueCross方法中修改的只是自己棧中的內容,並沒有修改main方法棧中的內容

 

引用傳遞

”引用”也就是指向真實內容的地址值,在方法調用時,實參的地址通過方法調用被傳遞給相應的形參,在方法體內,形參和實參指向同一塊內存地址,對形參的操作會影響的真實內容。

 

 先有一個Person類代碼如下:

public class Person {
	
	private String name;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	

}

  

 測試類代碼:

public class TestArr {
	
	
	public static void PersonCross(Person person) {
		 System.out.println("傳入的person的name:"+person.getName());
		 person.setName("敖丙");
		 System.out.println("方法內重新賦值后的name:"+person.getName());
	}
	
	public static void main(String[] args) {
		Person p=new Person();
		p.setName("哪吒");
		p.setAge(4);
		PersonCross(p);
		System.out.println("方法執行后的name:"+p.getName());
	}
	
}

  

測試結果1:

傳入的person的name:哪吒
方法內重新賦值后的name:敖丙
方法執行后的name:敖丙

  

我們可以看到PersonCross方法執行后,person的name值被改變了

 

下面再看一段代碼:

public class TestArr {
	public static void PersonCross(Person person) {
		 System.out.println("傳入的person的name:"+person.getName());
		 person=new Person();//新添加的代碼
		 person.setName("敖丙");
		 System.out.println("方法內重新賦值后的name:"+person.getName());
	}
	
	public static void main(String[] args) {
		Person p=new Person();
		p.setName("哪吒");
		p.setAge(4);
		PersonCross(p);
		System.out.println("方法執行后的name:"+p.getName());
	}
	
}

  

測試結果2:

傳入的person的name:哪吒
方法內重新賦值后的name:敖丙
方法執行后的name:哪吒

  

有沒有發現什么不同,這次PersonCross方法執行后person的name值並沒有改變,這又是為什么?

我們知道,java中的對象和數組是存放在堆內存中的,而堆內存是線程共享的,所以main方法執行時,會在堆內存中開辟一塊內存,用來存儲p對象的所有內容,然后再棧內存中創建一個引用p存儲堆區中p對象的真實地址,如下圖:

當執行到PersonCross方法時,因為方法內有這么一行代碼:person=new Person(),此時JVM在堆內存中又開辟了一塊內存空間,假設地址為xo2222,那么現在的person則指向了xo2222這塊內存,現在修改person的name值修改的是xo2222這塊內存空間的值,不會改變xo3333的值,所以測試結果2中的name沒有發生變化  

引用傳遞本質上就是值傳遞,將引用變量的值傳遞給形參,因為引用變量的值存放的是地址值,所以當地址值傳遞給形參后,形參和實參指向同一塊內存區域。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM