1. 程式人生 > >new的過程是怎樣的?看完這一篇就懂了

new的過程是怎樣的?看完這一篇就懂了

在現實世界中,找物件是一門學問,找物件不在於多而在於精 ![](https://ask.qcloudimg.com/http-save/4159932/2h9uw2fosy.jpeg) 在計算機世界中,**面向物件程式設計**的關鍵在於能否靈活地運用類,如何設計出一個符合需求的物件也是也是值得學習和思考的。 那麼,**面向物件程式設計**到底是什麼? 在**面向物件程式設計**中,肯定會涉及**類**和**物件**兩個概念。**類**是什麼?**物件**是什麼,兩者有什麼關係? 接下來就一 一地來解答這些疑惑吧 ![](https://ask.qcloudimg.com/http-save/4159932/yqtf73ar0g.jpeg) ## 類和物件 - 類,是指將相同屬性的東西放在放在一起,類是一個模板,能夠描述一類物件的狀態和行為 - 而物件,就是實際存在某個類中的一個個的個體,所以也被稱為例項(instance)。 - 物件的抽象是類,類的具體化就是物件,也就是類的例項就是物件。 在C語言中,結構體是資料的集合,它將資料捆綁在一起,使得我們可以將這些資料看作是一個整體。而對結構體中的資料 進行操作的函式就寫在結構體的外部。 而在面向物件程式設計中,將表示事物行為的函式也放入了這個整體,就形成了物件的概念。使得這個整體既描述屬性,又能描述行為。 所以,面向物件程式設計是一種將關注點置於**物件Object**本身的程式設計方法,物件的構成要素包含**物件的行為及操作**,以此基礎進行程式設計。 這種方法使得程式易於複用。OOP主要使用的**程式設計技巧**有:**繼承**、**封裝**、**多型**三種。 說了這麼多,是不是看暈了,沒關係,繼續往下看。 ## 現實世界中的抽象 - 類 在現實生活中,可以將人看成一個類,這類稱為人類(抽象類) 如果某個男孩想找一個物件(女朋友),那麼所有的女孩都是這個男孩選女朋友的範圍,所有的女孩就是一【類】 - 物件 如果這個時候男孩已經找到喜歡的物件了,他的女朋友名字叫【林允兒】。那麼假設這個名字是唯一的,此時名字叫【林允兒】的這個女孩就是一個物件(小聲bb,其實{她是我老婆|hē hē hē hē}狗頭) ![](https://ask.qcloudimg.com/http-save/4159932/1ryzz8d306.jpeg) **接下來通過具體的程式碼來講解一下** ``` // FileName: Person.java public abstract class Person { protected int age; protected String name; public Person(int age,String name) { this.age = age; this.name = name; } public abstract void speak(); public abstract void sayInfo(Person person); } ``` 在這裡,定義了一個**抽象類-人**,在人的這個抽象類裡面,包含了人的一些**屬性**和**行為**,代表了人具有的**共同屬性** 然後,定義了一個**子類Man**和**子類Woman**繼承**父類Person**,裡面包含了共同擁有的屬性,並增加了性別sex,然後對方法進行了**重寫** ``` // FileName: Man.java public class Man extends Person { private String sex = "man"; public Man(int age,String name) { super(age,name); } @Override public void speak() { System.out.println("我的名字是: " + super.name + "\n" + "我今年" + super.age + "歲了."); }; @Override public void sayInfo(Person person) { System.out.println("我的女朋友是:" + person.name + "\n" + "她今年" + person.age + "歲了."); } } ``` --- ``` // FileName: WoMan.java public class WoMan extends Person { private String sex = "woman"; public WoMan(int age,String name) { super(age,name); } @Override public void speak() { System.out.println("我的名字是: " + super.name + "\n" + "我今年" + super.age + "歲了."); }; @Override public void sayInfo(Person person) { System.out.println("我的男朋友是:" + person.name + "\n" + "她今年" + person.age + "歲了."); } } ``` **那麼,他們的關係就是如下圖:** ![](https://ask.qcloudimg.com/http-save/4159932/4v4kqwc2c9.png) `所以,一個類的基本組成為下圖:` ![](https://ask.qcloudimg.com/http-save/4159932/2r8ao8w7l6.png) 那麼,我們再來編寫下測試程式碼: ``` // FileName: TestPerson.java public class TestPerson { /** * @param args */ public static void main(String[] args) { Person codevald = new Man(21,"codevald"); Person lye = new Woman(20,"linyuer"); codevald.speak(); codevald.sayInfo(lye); lye.speak(); lye.sayInfo(codevald); } } ``` 執行結果: ![](https://ask.qcloudimg.com/http-save/4159932/03wlty6m0p.png) 接下來,是最有意思的部分,我們來分析下程式碼中**new**的時候發生了什麼。 ## new操作的過程 `當我們new一個物件的時候JVM首先會去找到對應的類元資訊,如果找不到意味著類資訊還沒有被載入,所以在物件建立的時候也可能會觸發類的載入操作。當類元資訊被載入之後,我們就可以通過類元資訊來確定物件資訊和需要申請的記憶體大小。` ### 物件建立的流程 ### 1.構建物件 首先main執行緒會在棧中申請一個屬於自己的棧空間,然後我們呼叫main方法的時候,會生成一個main方法的棧幀,然後執行new Man(),這裡會根據Man類的元資訊先確定物件的大小,然後在JVM堆裡申請一塊記憶體區域並構建物件,同時對Man物件成員變數資訊 並賦予預設值(在這裡會涉及多型,在記憶體中的分配情況有機會再解釋解釋)。 ![](https://ask.qcloudimg.com/http-save/4159932/rqpod7xubv.png) ### 2.初始化物件 這一步會執行物件內部的init方法,初始化成員變數值,即執行物件的構造方法(這裡呼叫父類的構造方法進行賦值),構造方法執行完,此時的age = 21,name = "codevald"。 ![](https://ask.qcloudimg.com/http-save/4159932/4wcq5h4l7r.png) ### 3.引用物件 物件例項化完成之後,再把棧中的Person物件引用地址指向Man物件在堆記憶體中的地址 ![](https://ask.qcloudimg.com/http-save/4159932/qp0gmgiuaf.png) ### 4.繼續構造、初始化,引用物件物件 這一步和上面三個步驟一樣,就不詳細說了 附上圖 ![](https://ask.qcloudimg.com/http-save/4159932/vccll1hto4.png) ![](https://ask.qcloudimg.com/http-save/4159932/nf1ndp79gw.png) ![](https://ask.qcloudimg.com/http-save/4159932/211koy1w3n.png) ### 5.呼叫方法 呼叫speak()方法的時候,會先找到Person物件(**codevald**)中的引用地址,找到真正的在堆記憶體中的**Man物件**,執行speak()方法,執行的時候,會呼叫父類中的成員變數,所以會找到堆記憶體中的父物件的成員變數(**name和age**),載入進來,進行輸出 `我的名字是: codevald 我今年21歲了.` ![](https://ask.qcloudimg.com/http-save/4159932/vzhb6y1pqw.png) 呼叫sayInfo()方法的時候,一樣先找到物件(codevald)中的引用地址,找到真正的在堆記憶體中的Man物件,執行sayInfo()方法,執行的時候,會找到Person物件(linyuner)的地址,即指向堆記憶體中的Woman物件,找到父類裡面的成員變數(**name和age**),進行輸出 `我的女朋友是:linyuer 她今年20歲了.` ![](https://ask.qcloudimg.com/http-save/4159932/886gviqskd.png) _**下面的程式碼的執行過程同理,就留給小夥伴們自行去分析啦~**_ 附上TestPerson的位元組碼檔案,感興趣的小夥伴可以自行檢視進行分析 ``` Compiled from "TestPerson.java" public class person.TestPerson { public person.TestPerson(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."