java面试题解惑系列(五)——传了值还是传了引用?_JAVA面試題解惑系列(五)——傳了值還是傳了引用? | 學步園...

JAVA中的傳遞都是值傳遞嗎?有沒有引用傳遞呢?

在回答這兩個問題前,讓我們首先來看一段代碼:

Java代碼

public class ParamTest {

// 初始值為0

protected int num = 0;

// 為方法參數重新賦值

public void change(int i) {

i = 5;

}

// 為方法參數重新賦值

public void change(ParamTest t) {

ParamTest tmp = new ParamTest();

tmp.num = 9;

t = tmp;

}

// 改變方法參數的值

public void add(int i) {

i += 10;

}

// 改變方法參數屬性的值

public void add(ParamTest pt) {

pt.num += 20;

}

public static void main(String[] args) {

ParamTest t = new ParamTest();

System.out.println("參數--基本類型");

System.out.println("原有的值:" + t.num);

// 為基本類型參數重新賦值

t.change(t.num);

System.out.println("賦值之後:" + t.num);

// 為引用型參數重新賦值

t.change(t);

System.out.println("運算之後:" + t.num);

System.out.println();

t = new ParamTest();

System.out.println("參數--引用類型");

System.out.println("原有的值:" + t.num);

// 改變基本類型參數的值

t.add(t.num);

System.out.println("賦引用後:" + t.num);

// 改變引用類型參數所指向對象的屬性值

t.add(t);

System.out.println("改屬性後:" + t.num);

}

}

這段代碼的運行結果如下:

參數--基本類型

原有的值:0

賦值之後:0

運算之後:0

參數--引用類型

原有的值:0

賦引用後:0

改屬性後:20

從上面這個直觀的結果中我們很容易得出如下結論:

對於基本類型,在方法體內對方法參數進行重新賦值,並不會改變原有變量的值。

對於引用類型,在方法體內對方法參數進行重新賦予引用,並不會改變原有變量所持有的引用。

方法體內對參數進行運算,不影響原有變量的值。

方法體內對參數所指向對象的屬性進行運算,將改變原有變量所指向對象的屬性值。

上面總結出來的不過是我們所看到的表面現象。那麼,為什麼會出現這樣的現象呢?這就要說到值傳遞和引用傳遞的概念了。這個問題向來是頗有爭議的。

大家都知道,在JAVA中變量有以下兩種:

基本類型變量,包括char、byte、short、int、long、float、double、boolean。

引用類型變量,包括類、接口、數組(基本類型數組和對象數組)。

當基本類型的變量被當作參數傳遞給方法時,JAVA虛擬機所做的工作是把這個值拷貝了一份,然後把拷貝後的值傳遞到了方法的內部。因此在上面的例子中,我們回頭來看看這個方法:

Java代碼

// 為方法參數重新賦值

public void change(int i) {

i = 5;

}

在這個方法被調用時,變量i和ParamTest型對象t的屬性num具有相同的值,卻是兩個不同變量。變量i是由JAVA虛擬機創建的作用域在change(int i)方法內的局部變量,在這個方法執行完畢後,它的生命周期就結束了。在JAVA虛擬機中,它們是以類似如下的方式存儲的:

[img]http://zangweiren.javaeye.com/upload/picture/pic/17754/bf858157-cd1b-3e9e-9fd1-374906bfd90f.jpg[/img]

很明顯,在基本類型被作為參數傳遞給方式時,是值傳遞,在整個過程中根本沒有牽扯到引用這個概念。這也是大家所公認的。對於布爾型變量當然也是如此,請看下面的例子:

Java代碼

public class BooleanTest {

// 布爾型值

boolean bool = true;

// 為布爾型參數重新賦值

public void change(boolean b) {

b = false;

}

// 對布爾型參數進行運算

public void calculate(boolean b) {

b = b && false;

// 為了方便對比,將運算結果輸出

System.out.println("b運算後的值:" + b);

}

public static void main(String[] args) {

BooleanTest t = new BooleanTest();

System.out.println("參數--布爾型");

System.out.println("原有的值:" + t.bool);

// 為布爾型參數重新賦值

t.change(t.bool);

System.out.println("賦值之後:" + t.bool);

// 改變布爾型參數的值

t.calculate(t.bool);

System.out.println("運算之後:" + t.bool);

}

}

輸出結果如下:

參數--布爾型

原有的值:true

賦值之後:true

b運算後的值:false

運算之後:true

那麼當引用型變量被當作參數傳遞給方法時JAVA虛擬機又是怎樣處理的呢?同樣,它會拷貝一份這個變量所持有的引用,然後把它傳遞給JAVA虛擬機為方法創建的局部變量,從而這兩個變量指向了同一個對象。在篇首所舉的示例中,ParamTest類型變量t和局部變量pt在JAVA虛擬機中是以如下的方式存儲的:

[img]http://zangweiren.javaeye.com/upload/picture/pic/17756/3c3c237f-bd06-3e7a-a0d9-a2317754b560.jpg[/img]

有一種說法是當一個對象或引用類型變量被當作參數傳遞時,也是值傳遞,這個值就是對象的引用,因此JAVA中只有值傳遞,沒有引用傳遞。還有一種說法是引用可以看作是對象的別名,當對象被當作參數傳遞給方法時,傳遞的是對象的引用,因此是引用傳遞。這兩種觀點各有支持者,但是前一種觀點被絕大多數人所接受,其中有《Core Java》一書的作者,以及JAVA的創造者James Gosling,而《Thinking in Java》一書的作者Bruce Eckel則站在了中立的立場上。

我個人認為值傳遞中的值指的是基本類型的數值,即使對於布爾型,雖然它的表現形式為true和false,但是在棧中,它仍然是以數值形式保存的,即0表示false,其它數值表示true。而引用是我們用來操作對象的工具,它包含了對象在堆中保存地址的信息。即使在被作為參數傳遞給方法時,實際上傳遞的是它的拷貝,但那仍是引用。因此,用引用傳遞來區別與值傳遞,概念上更加清晰。

最後我們得出如下的結論:

1、基本類型和基本類型變量被當作參數傳遞給方法時,是值傳遞。在方法實體中,無法給原變量重新賦值,也無法改變它的值。

2、對象和引用型變量被當作參數傳遞給方法時,在方法實體中,無法給原變量重新賦值,但是可以改變它所指向對象的屬性。至於到底它是值傳遞還是引用傳遞,這並不重要,重要的是我們要清楚當一個引用被作為參數傳遞給一個方法時,在這個方法體內會發生什麼。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值