Java方法傳參方式記住了兩點(diǎn)。基本上不會(huì)犯錯(cuò)誤。
- 方法內(nèi)修改基礎(chǔ)數(shù)據(jù)類型(數(shù)字類型或布爾類型)不會(huì)改變方法外的參數(shù);
- 方法內(nèi)修改對(duì)象(包含數(shù)組)狀態(tài)會(huì)同步修改方法方法外的參數(shù)。
程序片段1來(lái)驗(yàn)證第一點(diǎn):
public static void main(String[] args) {
Integer a = 5;
System.out.println("入棧前 a = " + a);
calc(a);
System.out.println("出棧后 a = " + a);
}
private static void calc(Integer a) {
a = a * 3;
System.out.println("棧內(nèi)計(jì)算 a = " + a);
}
程序的運(yùn)行結(jié)果為:
入棧前 a = 5
棧內(nèi)計(jì)算 a = 15
出棧后 a = 5
程序片段2來(lái)驗(yàn)證第二點(diǎn)
public static void main(String[] args) {
Stu tom = new Stu(30, "tom");
System.out.println("入棧前 tom = " + tom);
doubleScore(tom);
System.out.println("出棧后 tom = " + tom);
}
private static void doubleScore(Stu tom) {
tom.score = tom.score * 2;
System.out.println("棧內(nèi)計(jì)算 tom = " + tom);
}
private static class Stu {
String name;
int score;
public Stu(int score, String name) {
this.score = score;
this.name = name;
}
@Override
public String toString() {
return "[ name='" + name + '\'' + ", score=" + score + ']';
}
}
片段2的運(yùn)行結(jié)果為:
入棧前 tom = [ name='tom', score=30]
棧內(nèi)計(jì)算 tom = [ name='tom', score=60]
出棧后 tom = [ name='tom', score=60]
從兩段程序的結(jié)果看,片段1的基礎(chǔ)數(shù)據(jù)參數(shù)用值傳遞來(lái)解釋的通;片段2的對(duì)象參數(shù)用引用傳遞也行的通。
究竟參數(shù)傳遞采用哪種方式呢,特地翻了 Java編程思想第四版 第12章 傳遞和返回對(duì)象 中給出了解釋,Java中所有參數(shù)或自變量都是通過(guò)句柄的方式傳遞的,向方法中傳遞一個(gè)參數(shù)時(shí),實(shí)際上傳遞的只是指向外部對(duì)象的一個(gè)句柄。
看清楚了嗎,人家根本不關(guān)心什么值傳遞、引用傳遞,實(shí)際上問(wèn)題的關(guān)鍵是怎么理解 句柄。
- Java按值傳遞任何東西。句柄當(dāng)做指針,傳遞對(duì)象就是拷貝對(duì)象的地址值,參數(shù)也指向該對(duì)象,方法內(nèi)對(duì)象狀態(tài)改外部對(duì)象也會(huì)改變;基礎(chǔ)數(shù)據(jù)類型就更明顯,基礎(chǔ)數(shù)據(jù)傳入方法會(huì)得到一個(gè)數(shù)據(jù)的副本,所以一切傳參都是按值傳遞。
- Java主要按值傳遞,但對(duì)象卻是引用傳遞。句柄看做對(duì)象的一個(gè)“別名”,由于對(duì)象傳入方法沒有獲得一個(gè)本地副本,所以對(duì)象傳遞顯然不是值傳遞,而是引用傳遞。
句柄 的理解不同帶來(lái)了不同的結(jié)果,原書的作者直接回避了這個(gè)問(wèn)題,也許java的設(shè)計(jì)者壓根沒有考慮這個(gè)問(wèn)題,才會(huì)后面的爭(zhēng)議。
還有一點(diǎn)一定要記住,記為第三點(diǎn):
- 方法不能改變對(duì)象參數(shù)的引用
程序片段3來(lái)驗(yàn)證第3點(diǎn):
public static void main(String[] args) {
Stu tom = new Stu(30, "tom");
System.out.println("入棧前 tom = " + tom);
convert(tom);
System.out.println("出棧后 tom = " + tom);
}
private static void convert(Stu tom) {
tom = new Stu(50, "jack");
System.out.println("棧內(nèi)計(jì)算 tom = " + tom);
}
程序片段3來(lái)運(yùn)行結(jié)果:
入棧前 tom = [ name='tom', score=30]
棧內(nèi)計(jì)算 tom = [ name='jack', score=50]
出棧后 tom = [ name='tom', score=30]
總結(jié)
不管一切按值傳遞,還是主要按值傳遞,從這三個(gè)特點(diǎn)來(lái)講都解釋的通,沒必要為概念糾結(jié),明白特性才是關(guān)鍵!