Java中參數傳遞是值傳遞,還是引用傳遞的一次深究
是我自己分析的,可能不準確,請大牛們指導,歡迎大家拍磚
1 先回顧一下java基礎內容:對象在內存分配方式
public static void main(String[] args)
{
Person p = new Person();
}
這一句"Person p = new Person();" 分配了兩個對象.
一個是引用對象p分配在棧中,
一個是實體對象new Person(),分配在堆上
並且p保存了實體對象的地址
如下圖所示
棧內存 堆內存
引用對象p指向了 一個實體對象 Person.
對於堆上和棧上分配內存的釋放,有java基礎的人都知道,在這裏就不說了。不知道可以百度。
2 函數中參數傳遞的兩種類型
2.1 參數類型爲基本類型 如 int float 等等
基本類型傳遞舉例
public class PersonDemo
{
public static void main(String[] args)
{
int n =100;
System.out.println(n);
changeN(n);
System.out.println(n);
}
public static int changeN(int a)
{
return a = a+1;
}
}
相信大家都知道結果:
100
100
從這裏,我們都可以看出java中方法的參數傳遞是按值傳遞的。
2.2 參數類型爲對象類型 如Person
例子一
public class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
p.age = 10;
System.out.println("傳遞前age=" +p.age);
changeAge(p);
System.out.println("傳遞後age=" +p.age);
}
public static int changeN(int a)
{
return a = a+1;
}
public static void changeAge(Person per)
{
per.age += 10;
}
}
class Person
{
int age;
}
輸出結果:
傳遞前age=10
傳遞後age=20
可能有人會想 例子一這裏傳遞的是對象的引用。
例子二
public class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
p.age = 10;
System.out.println("傳遞前age=" +p.age);
changePerson(p);
System.out.println("傳遞後age=" +p.age);
}
public static int changeN(int a)
{
return a = a+1;
}
public static void changeAge(Person per)
{
per.age += 10;
}
public static void changePerson(Person per)
{
Person p1 = new Person();
p1.age = 50;
per =p1;
}
}
class Person
{
int age;
}
輸出結果
傳遞前age=10
傳遞後age=10
可能有人會想 例子二中這裏傳遞的是對象的引用的一個複製。
對於例子二我想了一個圖示
對於第二種參數傳入類型爲對象的情況,解釋有3種
說法1 參數是按引用傳遞的,對於說法1 還有兩種解釋,
解釋1 引用傳遞時是傳入對象的引用
解釋2 引用傳遞時是傳入對象引用的複製
說法2 參數是按值傳遞
到底關於對象類型的參數,java中是按什麼傳遞的,
其實java中不管是對象參數還是基本類型參數,都是按值傳遞的。
我們可以對方法中參數某些值進行打印 比如 Hashcode
這是部分代碼 Person類可以參考上面定義的。
public class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
System.out.println("傳遞前hascode=" +p.hashCode());
hc(p);
}
public static void hc(Person per)
{
System.out.println("傳遞後hascode=" +per.hashCode());
}
}
輸出結果
傳遞前hascode=29855319
傳遞後hascode=29855319
我們可以看出 參數中傳遞進來的對象的hashcode和參數外面的一樣。
我們再看一個例子
public class PersonDemo
{
static Person CP = new Person();
public static void main(String[] args)
{
equalPer(CP);
}
public static void equalPer(Person per)
{
System.out.println("比較對象結果:" +(per == CP));
}
}
輸出結果
比較對象結果:true
用==進行比較, 我們一直都認爲是比較的值相等,而不是內容。
查看JDK文檔中隊 hashcode方法的描述,有這麼一段話
實際上,由 Object 類定義的 hashCode 方法確實會針對不同的對象返回不同的整數。
這一般是通過將該對象的內部地址轉換成一個整數來實現的,但是 JavaTM 編程語言不需要這種實現技巧。)
通過上面的分析,關於對象傳遞,傳遞的是對象的一個引用(這裏的引用跟c++中的引用不是一回事),這裏的引用對象
是"該對象的內部地址轉換成一個整數" ,其實就是一個整數。
所以我們可以肯定了java中不管是對象參數還是基本類型參數,都是按值傳遞的。
附帶說明:
c++裏面關於對象的一些知識
c++也是面向對象的語言,c++裏面建立對象的方法是 :Person * p1 = new Person;
new出來返回的是一個對象的指針,java中沒有指針這個說法。
而這個棧上的指針p也是指向堆上的new Person對象。
貌似跟java很類似,的確很類似 如果你在c++中也實現類似的改變Person中age的方法
public void changeAge(Person * p)
{
p->age += 10;
}
他也改變 Person中age的值。他傳入的是一個指針類型,從這個角度可以看出,C++中傳遞是按值傳遞的。
C++中按引用傳遞的方式是這樣的
public void changeAge(Person & p)
{
p.age += 10;
}