天天看點

java參數傳遞時到底是值傳遞還是引用傳遞

java參數傳遞時到底是值傳遞還是引用傳遞(baidu搜集)

最近比較長一段時間以來,網上的IT同行裡面比較流行“JAVA面試32問”,很多人的BLOG裡都引用這些面試題,最近因為工作内容比較枯燥,也來看看這些試題以調節一下口味,其中有一道題讓我很費解。

原題是:當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,并可傳回變化後的結果,那麼這裡到底是值傳遞還是引用傳遞?

用google查詢結果,得到答案基本上是:值傳遞。當時覺得挺納悶兒,為什麼連參數的内容都被修改了,怎麼還能說是“值傳遞”呢?因為在傳統的印象裡(尤其是從C++過來以後),值傳遞都應該是不改變原參數的。

問問周圍的同僚,也大都這麼講,但是也都講不清這種理論的根源是什麼。我這個人有個毛病,有事情想不通時就會憋得難受,後來在《Thinking in Java》的一段内容(注解[1])裡找到了自己的結論,我認為(《Thinking in Java》的作者也這麼認為):可以說是值傳遞,也可以說是引用傳遞。

一,認為是值傳遞。得出這種結論的前提必須是“參數的值就是對該對象的引用,而不是對象的内容”,這句話可能有些費解,舉個例子加以說明。

public class Paier {

     public static void main(String[] args) {

                    Paier paier = new Paier();

                    paier.test();

     }

     public void test() {

                    TestClass para1 = new TestClass();

                    para1.setTest(new Integer(10));

                    TestClass result1 = test1(para1);

                    System.out.println("para1   = " + para1.getTest());

                    System.out.println("result1 = " + result1.getTest());

                    TestClass para2 = new TestClass();

                    para2.setTest(new Integer(10));

                    TestClass result2 = test2(para2);

                    System.out.println("para2   = " + para2.getTest());

                    System.out.println("result2 = " + result2.getTest());

     }

     public TestClass test1(TestClass t) {

                    t = new TestClass();

                    t.setTest(new Integer(20));

                    return t;

     }

     public TestClass test2(TestClass t) {

                    t.setTest(new Integer(20));

                    return t;

     }

     class TestClass {

                    Integer test = null;

                    public void setTest(Integer i) {

                                  test = i;

                    }

                    public Integer getTest() {

                                  return test;

                    }

     }

}

執行後的結果是:

para1   = 10

result1 = 20

para2   = 20

result2 = 20

為什麼會這樣呢?因為test1想通過修改參數的引用來修改傳回值,但是在JAVA中,參數的引用是不可修改的,是以para1和result1分别指向不同的空間,結果也不一樣。而在test2中,result2和para2始終指向同一塊區域,test2方法修改的是參數内容,而不是參數的引用。

從上面看來,因為參數的引用不可改變,如果了解為“參數的值就是對該對象的引用”,那麼java自然隻有值傳遞。

二,認為是引用傳遞。還是上面的例子,如果在參數傳遞時了解為“參數的值就是該對象的内容”,那麼顯然不是值傳遞,因為對象的内容已經改變了。

認為是引用傳遞還有一個理由,就是java有一個保留字byvalue,現在的JDK版本中還沒有實作這個保留字,似乎是在暗示對這種觀點的支援。(There appears to be some support for this view within Sun, since one of the “reserved but not implemented” keywords is byvalue.)

是以說,對于原題的結論,是值傳遞還是引用傳遞并不重要,重要的是要了解“對象的内容可以在被調用的方法中改變,但對象的引用是永遠不會改變的。”

注解[1]:下面是在《Thinking in Java》中的原文:

This brings up the terminology issue, which always seems good for an argument. The term is “pass by value,” and the meaning depends on how you perceive the operation of the program. The general meaning is that you get a local copy of whatever you’re passing, but the real question is how you think about what you’re passing. When it comes to the meaning of “pass by value,” there are two fairly distinct camps:

1.      Java passes everything by value. When you’re passing primitives into a method, you get a distinct copy of the primitive. When you’re passing a handle into a method, you get a copy of the handle. Ergo, everything is pass by value. Of course, the assumption is that you’re always thinking (and caring) that handles are being passed, but it seems like the Java design has gone a long way toward allowing you to ignore (most of the time) that you’re working with a handle. That is, it seems to allow you to think of the handle as “the object,” since it implicitly dereferences it whenever you make a method call.

2.      Java passes primitives by value (no argument there), but objects are passed by reference. This is the world view that the handle is an alias for the object, so you don’t think about passing handles, but instead say “I’m passing the object.” Since you don’t get a local copy of the object when you pass it into a method, objects are clearly not passed by value. There appears to be some support for this view within Sun, since one of the “reserved but not implemented” keywords is byvalue. (There’s no knowing, however, whether that keyword will ever see the light of day.)

Having given both camps a good airing and after saying “It depends on how you think of a handle,” I will attempt to sidestep the issue for the rest of the book. In the end, it isn’t that important – what is important is that you understand that passing a handle allows the caller’s object to be changed unexpectedly.