一、前言
首先先說結論,Java中方法參數傳遞方式是按值傳遞。如果參數是基本類型,傳遞的是基本類型的字面量值的拷貝。如果參數是引用類型,傳遞的是該參量所引用的對象在堆中地址值的拷貝。
接下來深入了解一下為什么是值傳遞,要想知道Java到底是傳值還是傳引用,首先要知道基本類型和引用類型的區別。
二、深入了解參數傳遞
1.基本類型 和 引用類型的不同之處
基本類型包括8種數據類型:int、short、long、byte、char、float、double、boolean,在方法中定義的非全局基本數據類型變量的具體內容是存儲在棧中的;除了基本類型以外的都是引用類型:類、接口類型、數組類型、字符串類型都是引用類型,引用類型變量其具體內容都是存放在堆中的,而棧中存放的是其具體內容所在內存的地址(字符串類型比較特殊,涉及到字符串常量池,這里不做深入研究)。
示例:
int num = 10; String str = new String("hello");
注:該圖的堆區是經過簡化的,實際的情況會復雜點,這里只作示意
如圖所示,num是基本類型,值就直接保存在變量中。而str是引用類型,變量中保存的只是實際對象的地址。一般稱這種變量為"引用",引用指向實際對象,實際對象在堆中並保存着實際內容。
2.賦值運算符(=)的作用
num = 20;
str = "world";

public static void main(String[] args) { Test test = new Test(); int i = 10; test.print(10); System.out.println("main方法輸出i:" + i); } public void print(int j) { j = 20; System.out.println("print方法輸出j:" + j); }
結果:
print方法輸出j:20
main方法輸出i:10
這個例子應該還是很好理解的,test.print(10)將10作為參數傳給print方法, 將10拷貝一份給 j,修改 j 不會影響 i 。
例子二(引用數據類型):
public static void main(String[] args) { Test test = new Test(); User user = new User(); user.setName("Tom"); user.setAge("18"); test.print(user); System.out.println("main方法輸出用戶:" + user); } public void print(User user1) { user1.setName("Mike"); System.out.println("print方法輸出用戶:" + user1); }
結果:
print方法輸出用戶:User{name="Mike",age="18"}
main方法輸出用戶:User{name="Mike",age="18"}
解釋: test.print(user)將user對象的引用(即user對象的內存地址)拷貝一份給形參的user1,也就是說main方法中的user引用和print方法的user1引用都指向堆中的同一個user對象,所以user1修改user對象的數據,user的也會相應的改變。
user1.setName("Mike")執行前:
user1.setName("Mike")執行后:
public static void main(String[] args) { Test test = new Test(); String name = new String("Tom"); test.print(name); System.out.println("main方法輸出name:" + name); } public void print(String name1) { name1 = "Mike"; System.out.println("print方法輸出name1:" + name1); }
結果:
print方法輸出name1:Mike
main方法輸出name:Tom
解釋:由於String被設計成為了不可變類型,為name賦值時不會覆蓋以前的對象而是創建一個新的字符串對象並返回引用。
name1 = "Mike"執行前:
name1 = "Mike"執行后:
三、總結
Java中方法參數傳遞方式是按值傳遞。如果參數是基本類型,傳遞的是基本類型的數據拷貝。如果參數是引用類型,因為棧中存的是對象的地址值,所以傳遞的是該參量所引用的對象在堆中地址值的拷貝,除了特殊的String類型,形參對象可以影響實參對象的值。