值傳遞:方法調用時,實際參數把它的值傳遞給對應的形式參數,方法執行中形式參數值的改變不影響實際參數的值。
引用傳遞:也稱為傳地址。方法調用時,實際參數的引用(地址,而不是參數的值)被傳遞給方法中相對應的形式參數,在方法執行中,對形式參數的操作實際上就是對實際參數的操作,方法執行中形式參數值的改變將會影響實際參數的值。
而在JAVA中只有值傳遞,基本類型傳遞的是值的副本,引用類型傳遞(不是上面說的引用傳遞)的是引用的副本。下面來看幾個例子:
1.在函數中傳遞基本數據類型
1 public class TestValue { 2 public static void main(String[] args) { 3 int i = 3; 4 int j = 4; 5 change(i,j); 6 System.out.println(i); 7 System.out.println(j); 8 } 9 public static void change(int i,int j){ 10 int temp = i; 11 i = j; 12 j = temp; 13 } 14 }
結果顯示i和j並沒有發生交換。因為參數中傳遞的是基本數據類型i和j的副本,在函數中交換的也是副本的值而不是數據本身!
2.在函數中傳遞引用數據類型
1 public class TestValue1 { 2 public static void change(int[] count){ 3 count[0] =10; 4 } 5 public static void main(String[] args) { 6 int[] count = {1,2,3,4,5}; 7 change(count); 8 System.out.println(count[0]); 9 } 10 }
結果count[0]發生了變化,等於10。在方法中傳遞的是int數組,實際上傳遞的是其引用count的副本,他們都指向數組對象,即對備份所調用的方法更改的是同一個對象。
3.重點來看看下面這個例子(轉)
class Student{ private float score; public Student(float score) { this.score = score; } public void setScore(float score) { this.score = score; } public float getScore() { return score; } } public class ParamTest { public static void main(String[] args) { Student a = new Student(0); Student b = new Student(100); System.out.println("交換前:"); System.out.println("a的分數:" + a.getScore() + "--- b的分數:" + b.getScore()); swap(a, b); System.out.println("交換后:"); System.out.println("a的分數:" + a.getScore() + "--- b的分數:" + b.getScore()); } public static void swap(Student x, Student y) { Student temp = x; x = y; y = temp; } }
【運行結果】:交換前:a的分數:0.0--- b的分數:100.0
交換后:a的分數:0.0--- b的分數:100.0
可以看出,兩者並沒有實現交換。這是為何?接下來一步一步看看swap調用的過程:
- 將對象a,b的拷貝(還是值傳遞)分別賦值給x,y,此時a和x指向同一對象,b和y指向同一對象
- swap方法體完成x,y的的交換,此時a,b並沒有變化
- 方法執行完成,x和y不再使用,a依舊指向new Student(0),b指向new Student(100)
本質是a和b分別指向了兩個不同的堆內存空間。