很多人看到這個可能都很疑惑室囊,Java不是分為值傳遞和引用傳遞嘛?怎么會都是值傳遞呢秘噪?
確實狸吞,在很多時候我們都會說:Java傳遞分為值傳遞(基本數(shù)據(jù))和引用傳遞(引用數(shù)據(jù):對象、字符串),這是最容易接受的蹋偏。但是便斥,仔細查閱資料發(fā)現(xiàn),Java中只有值傳遞威始。
那么為什么還要區(qū)分值傳遞和引用傳遞呢枢纠?
public class CallByValue {
private static int x=10;
public static void updateValue(int value){
value = 3 * value;
}
public static void main(String[] args) {
System.out.println("調(diào)用前x的值:"+x);
updateValue(x);
System.out.println("調(diào)用后x的值:"+x);
}
運行結(jié)果:
調(diào)用前x的值:10
調(diào)用后x的值:10
可以看到x的值并沒有變化,接下來我們一起來看一下具體的執(zhí)行過程:
分析:
- value被初始化為x值的一個拷貝(也就是10)
- value被乘以3后等于30黎棠,但注意此時x的值仍為10晋渺!
- 這個方法結(jié)束后,參數(shù)變量value不再使用葫掉,被回收些举。
結(jié)論:當傳遞方法參數(shù)類型為基本數(shù)據(jù)類型(數(shù)字以及布爾值)時,一個方法是不可能修改一個基本數(shù)據(jù)類型的參數(shù)俭厚。
當然java中除了基本數(shù)據(jù)類型還有引用數(shù)據(jù)類型户魏,也就是對象引用,那么對于這種數(shù)據(jù)類型又是怎么樣的情況呢挪挤?
聲明一個User對象類型:
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name=name;
this.age=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;
}
}
執(zhí)行類如下:
public class CallByValue {
private static User user=null;
public static void updateUser(User student){
student.setName("Lishen");
student.setAge(18);
}
public static void main(String[] args) {
user = new User("zhangsan",26);
System.out.println("調(diào)用前user的值:"+user.toString());
updateUser(user);
System.out.println("調(diào)用后user的值:"+user.toString());
}
運行結(jié)果:
調(diào)用前user的值:User [name=zhangsan, age=26]
調(diào)用后user的值:User [name=Lishen, age=18]
很顯然叼丑,User的值被改變了,也就是說方法參數(shù)類型如果是引用類型的話扛门,引用類型對應的值將會被修改
分析:
- student變量被初始化為user值的拷貝鸠信,這里是一個對象的引用。
- 調(diào)用student變量的set方法作用在這個引用對象上论寨,user和student同時引用的User對象內(nèi)部值被修改星立。
- 方法結(jié)束后,student變量不再使用葬凳,被釋放绰垂,而user還是沒有變,依然指向User對象火焰。
結(jié)論:當傳遞方法參數(shù)類型為引用數(shù)據(jù)類型時劲装,一個方法將修改一個引用數(shù)據(jù)類型的參數(shù)所指向?qū)ο蟮闹怠?/p>
通過上面的實例我們可能就會覺得java同時擁有按值調(diào)用和按引用調(diào)用啊,可惜的是這樣的理解是有誤導性的昌简,雖然上面引用傳遞表面上體現(xiàn)了按引用調(diào)用現(xiàn)象占业,但是java中確實只有按值調(diào)用而沒有按引用調(diào)用。
下面我們通過一個反例來說明:
public class CallByValue {
private static User user=null;
private static User stu=null;
/**
* 交換兩個對象
* @param x
* @param y
*/
public static void swap(User x,User y){
User temp =x;
x=y;
y=temp;
}
public static void main(String[] args) {
user = new User("user",26);
stu = new User("stu",18);
System.out.println("調(diào)用前user的值:"+user.toString());
System.out.println("調(diào)用前stu的值:"+stu.toString());
swap(user,stu);
System.out.println("調(diào)用后user的值:"+user.toString());
System.out.println("調(diào)用后stu的值:"+stu.toString());
}
}
我們通過一個swap函數(shù)來交換兩個變量user和stu的值纯赎,在前面我們說過谦疾,如果是按引用調(diào)用那么一個方法可以修改傳遞引用所對應的變量值,也就是說如果java是按引用調(diào)用的話犬金,那么swap方法將能夠?qū)崿F(xiàn)數(shù)據(jù)的交換念恍,而實際運行結(jié)果是:
調(diào)用前user的值:User [name=user, age=26]
調(diào)用前stu的值:User [name=stu, age=18]
調(diào)用后user的值:User [name=user, age=26]
調(diào)用后stu的值:User [name=stu, age=18]
我們發(fā)現(xiàn)user和stu的值并沒有發(fā)生變化碎紊,也就是方法并沒有改變存儲在變量user和stu中的對象引用。swap方法的參數(shù)x和y被初始化為兩個對象引用的拷貝樊诺,這個方法交換的是這兩個拷貝的值而已,最終音同,所做的事都是白費力氣罷了词爬。在方法結(jié)束后x,y將被丟棄权均,而原來的變量user和stu仍然引用這個方法調(diào)用之前所引用的對象顿膨。
這個過程也充分說明了java程序設(shè)計語言對對象采用的不是引用調(diào)用,實際上是對象引用進行的是值傳遞叽赊,當然在這里我們可以簡單理解為這就是按值調(diào)用和引用調(diào)用的區(qū)別恋沃,而且必須明白即使java函數(shù)在傳遞引用數(shù)據(jù)類型時,也只是拷貝了引用的值罷了必指,之所以能修改引用數(shù)據(jù)是因為它們同時指向了一個對象囊咏,但這仍然是按值調(diào)用而不是引用調(diào)用。
String和StringBuffer
public class ReferencePkValue1 {
public static void main(String[] args){
ReferencePkValue1 pk=new ReferencePkValue1();
//String類似基本類型塔橡,值傳遞梅割,不會改變實際參數(shù)的值
String test1="Hello";
pk.change(test1);
System.out.println(test1);
//StringBuffer和StringBuilder等是引用傳遞
StringBuffer test2=new StringBuffer("Hello");
pk.change(test2);
System.out.println(test2.toString());
}
public void change(String str){
str=str+"world";
}
public void change(StringBuffer str){
str.append("world");
}
}
結(jié)果:
Hello
Helloworld
這里我們可以簡單地理解為:
String類似基本類型,值傳遞葛家,不會改變實際參數(shù)的值户辞;StringBuffer是引用傳遞
總結(jié):
- 基本數(shù)據(jù)類型傳值,對形參的修改不會影響實參癞谒;
- 引用類型傳引用底燎,形參和實參指向同一個內(nèi)存地址(同一個對象),所以對參數(shù)的修改會影響到實際的對象弹砚;
- 上面兩種傳遞都進行了值拷貝的過程双仍。
參考資料:
https://www.cnblogs.com/binyue/p/3862276.html
https://www.cnblogs.com/pan1042/p/11275497.html
https://www.cnblogs.com/laipDIDI/articles/2524309.html