Java編程思想閱讀筆記(一)值傳遞和引用傳遞

對引用類型的理解

對於Java中的引用類型,我我的的理解是:它在本質上,或者說底層實現上和C/C++中的指針是一模一樣的,只不過它對指針進行了假裝,使用上泛化、強化和簡單化,概念上淡化和弱化,沒有了C/C++中的 +-加減偏移、&取地址、*解引用、->訪問成員 等操做符。java

在C/C++中,能夠直接在棧上建立變量,而後使用標識符來訪問變量,如string s = "hello"; cout << s.length();;也可使用new在堆上建立變量,而後使用指針來訪問變量,如string* sptr = new string("hello"); cout << sptr->length();編程

而在Java中,對於基本類型,不用也不能用new來建立變量,而是建立一個並不是是引用的」自動「變量,這個變量直接存儲」值「,並置於棧中(這裏指的是方法中的局部變量,做爲類中的成員變量則另當別論),經過標識符直接訪問;而對於對象,一般是使用new來建立一個對象,存儲在堆上,只能經過相對應的引用類型來操做對象,這裏貼上 《Java編程思想》 中的一段話:post

全部這一切在Java裏都獲得了簡化。一切都被視爲對象,所以可採用單一固定的語法。儘管一切都看做對象,但操縱的標識符其實是對象的一個」引用「。能夠將這一情形想象成用遙控器(引用)來操縱電視機(對象)。只要握住這個遙控器,就能保持與電視機的鏈接。當有人想改變頻道或者減少音量時,實際操控的是遙控器(引用),再由遙控器來調控電視機(對象)。若是想在房間裏四處走走,同時仍能調控電視機,那麼只需攜帶遙控器(引用)而不是電視機(對象)。spa

以前說了Java中的引用類型本質上和指針是同樣的,也就是說引用類型變量的值其實是所引用的對象在堆中的地址,這裏看一張圖可能更方便理解:.net

引用和對象在JVM內存中的位置和關係

值傳遞仍是引用傳遞?

我我的以爲之因此不少人對Java中方法參數的傳遞方式有爭論,緣由有二:指針

  • 對值傳遞和引用傳遞的概念不清楚。
  • 將Java中引用類型中的「引用」和引用傳遞中的「引用」混爲一談,認爲基本類型的參數就是值傳遞,引用類型的參數就是引用傳遞。

既然這樣的話,在具體分析以前,先看一下值傳遞和引用傳遞的定義吧:code

定義

值傳遞:在方法被調用時,實參經過形參把它的內容副本傳入方法內部,此時形參接收到的內容是實參值的一個拷貝,所以在方法內對形參的任何操做,都僅僅是對這個副本的操做,不影響實參的內容。cdn

引用傳遞:」引用」也就是指向真實內容的地址值,在方法調用時,實參的地址經過方法調用被傳遞給相應的形參,在方法體內,形參和實參指向相同的內存地址,形參至關因而實參的一個「別名」,對形參的操做會影響的真實內容。對象

分析和結論

經過以上的定義,能夠看出值傳遞和引用傳遞的主要區別就是在方法體內對形參的操做會不會影響到實參的內容,那麼,實參的「內容」是什麼呢?對於基本類型的變量來講,它的內容固然就是所存儲的值,好比int num = 100;,它的內容就是100;對於引用類型的變量來講,它的內容是所引用的對象在堆中的地址,而不是所引用的對象自身,若是用以前貼上的 《Java編程思想》 中的一段文字裏舉的例子來講就是:遙控器的內容是芯片,而不是電視機blog

爲了加深理解,不妨再貼上一段Java代碼:

class Dog {
    public String name;
    public int age;
    // ...
}

class Test {
    public static void dosth2(Dog dog) {
        dog.name = "coffee";
        dog = null;
    }
    
    public static void dosth1() {
        Dog coffee = new Dog();
        dosth2(coffee);
        System.out.println(coffee.name);
    }
}
複製代碼

若是是引用傳遞的話,那麼dosth1中coffee的值在調用完dosth2後應該就變爲null了,第16行的代碼應該會報錯,然而事實上運行代碼的話,就會發現一切運行正常,說明並非引用傳遞。在這段代碼中,Dog類型的實例對象始終只有一個,它的內容也確實在dosth2中發生了改變,可是這跟我引用類型變量有什麼關係呢,兩個遙控器AB控制同一個電視機,A能讓電視機換臺,但它能換B的芯片嗎?

若是你對C++的語法比較熟悉的話,那麼就更好理解了。上述Java代碼中dosth2方法的形參聲明,在C++中應當寫成Dog* dog,一樣是值傳遞;可是在C++中值傳遞和引用傳遞二者都支持,若是想要使用引用傳遞的話,那麼就應當寫成Dog* &dog,只不過通常不會使用指針的引用罷了。然而在Java中有這種寫法嗎,支持Dog &dog這種寫法嗎,答案是並不資瓷,因此結論是:Java中只有值傳遞,沒有引用傳遞。

參考文章

這一次,完全解決Java的值傳遞和引用傳遞 - 掘金

對比C/C++,淺析Java裏的指針和引用 - CSDN

相關文章
相關標籤/搜索