本文旨在掃盲,深刻理解類、對象、引用三者之間的關係,在處理 a = b = c 這類問題上能夠有清晰無誤的思考。java
類是一個模板,它描述一類對象的行爲和狀態。this
拿一條狗來舉例,它的狀態有:名字、品種、顏色,行爲有:叫、搖尾巴和跑。指針
說白了,類就是咱們天然界的一些統稱,好比人、狗、車等。咱們已經在實際生活中,將一些事物主動劃分爲某一類,將這個概念延伸至軟件開發中,就是咱們本身所寫的 class 文件。code
具體將哪些事物劃分爲某一類是由咱們本身去調節的。好比,你能夠將狗劃分爲一類,可是狗中的杜賓犬也能夠成爲一類。舉個例子,一家專門出售杜賓犬的商店能夠對全部的杜賓犬進行編號,記錄每一個杜賓犬的姓名、飲食時間。對象
對象是類的一個實例,具備狀態和行爲。blog
若是說類是指的某一類,那麼對象就是這一類當中具體的一個事物。好比狗,具體起來又分爲拉布拉多、哈士奇,巴哥犬、吉娃娃等。它們都有本身獨特的狀態:名字、品種、顏色,以及獨特的行爲:叫、搖尾巴和跑。圖片
對比現實對象和軟件對象,它們之間十分類似。內存
軟件對象也有狀態和行爲。軟件對象的狀態就是屬性,行爲經過方法體現。開發
在軟件開發中,方法操做對象內部狀態的改變,對象的相互調用也是經過方法來完成。模板
類是咱們所寫的 class 文件,抽象出了一系列狀態和行爲,是咱們實例化具體對象的模板。
好比咱們有一個類(Dog.class),代碼以下:
public class Dog{ String breed; int age; String color; void barking(){ } void hungry(){ } void sleeping(){ }
在Java中,使用關鍵字new來建立一個新的對象。
new Dog();
經過 new 關鍵字,咱們完成了由抽象類實例化具體對象的步驟。而且在內存空間,多了一塊保存該實例對象的區域。如圖一所示:
對象已經 new 出來了,咱們如何發出指令來調用對象自身的屬性和方法呢?
還須要一個引用(reference)來幫咱們實現發出指令的操做。
Java中引用的代碼聲明以下:
Dog dog;
更清晰的理解能夠用圖二表示以下:
使用等號(=)將引用與對象進行連接,代碼以下:
Dog dog = new Dog();
更清晰的理解用圖三表示以下:
對象與引用的關係是一對多的關係,一個對象能夠被多個多個引用連接。如圖四所示:
由引用實現發出指令的操做,指令的執行是由對象自身完成的。好比下面這段代碼:
Dog dog = new Dog(); dog.sleeping()
在內存空間中的執行原理如圖五所示:
引用 dog 發出執行 sleeping() 方法的指令,具體的執行徹底是由內存中的 Dog 對象來完成的。
對於上述中的引用指向對象,執行的過程已經清晰明瞭,那麼對於引用指向引用的狀況又該如何去作呢?好比下面這段Java代碼:
Dog dog1 = new Dog(); Dog dog2 = dog1; dog1 = null; dog2.sleeping()
此時執行代碼的最後一行究竟會不會報錯呢?答案是不會。
由於引用A指向引用B,其實是指向引用B指向的內存空間,並非指向引用自己。
上述代碼用圖六表示以下:
引用能夠理解爲沒有空間的存在,只要使用引用就必須對其初始化賦值(可爲 NULL)。
在C語言的世界裏,沒有引用,只有指針。在Java的世界裏,沒有指針,只有引用。實際上,Java裏的引用就是C裏的指針,只是Java把這個指針封裝了起來,避免進行繁瑣的指針操做。
不運行代碼,你能夠分析出這段Java代碼的執行邏輯嗎?(推薦使用上面圖片的形式進行畫圖分析)
public class Node { Node prev; Node next; int id; public Node(int id) { this.id = id; } public static void main(String[] args) { Node e = new Node(1); e.next = new Node(2); e.next.next = new Node(3); Node hd = null, tl = null; do { Node p = new Node(e.id); if (tl == null) hd = p; else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); Node n = hd; do { System.out.println(n.id); }while ((n = n.next)!=null); } }