在現實世界中,找物件是一門學問,找物件不在于多而在于精

在計算機世界中,面向物件編程的關鍵在于能否靈活地運用類,如何設計出一個符合需求的物件也是也是值得學習和思考的,
那么,面向物件編程到底是什么?
在面向物件編程中,肯定會涉及類和物件兩個概念,類是什么?物件是什么,兩者有什么關系?
接下來就一 一地來解答這些疑惑吧

類和物件
- 類,是指將相同屬性的東西放在放在一起,類是一個模板,能夠描述一類物件的狀態和行為
- 而物件,就是實際存在某個類中的一個個的個體,所以也被稱為實體(instance),
- 物件的抽象是類,類的具體化就是物件,也就是類的實體就是物件,
在C語言中,結構體是資料的集合,它將資料捆綁在一起,使得我們可以將這些資料看作是一個整體,而對結構體中的資料
進行操作的函式就寫在結構體的外部,
而在面向物件編程中,將表示事物行為的函式也放入了這個整體,就形成了物件的概念,使得這個整體既描述屬性,又能描述行為,
所以,面向物件編程是一種將關注點置于物件Object本身的程式設計方法,物件的構成要素包含物件的行為及操作,以此基礎進行編程,
這種方法使得程式易于復用,OOP主要使用的編程技巧有:繼承、封裝、多型三種,
說了這么多,是不是看暈了,沒關系,繼續往下看,
現實世界中的抽象
- 類
在現實生活中,可以將人看成一個類,這類稱為人類(抽象類)
如果某個男孩想找一個物件(女朋友),那么所有的女孩都是這個男孩選女朋友的范圍,所有的女孩就是一【類】
- 物件
如果這個時候男孩已經找到喜歡的物件了,他的女朋友名字叫【林允兒】,那么假設這個名字是唯一的,此時名字叫【林允兒】的這個女孩就是一個物件(小聲bb,其實{她是我老婆|hē hē hē hē}狗頭)

接下來通過具體的代碼來講解一下
// 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 + "歲了.");
}
}
那么,他們的關系就是如下圖:

所以,一個類的基本組成為下圖:

那么,我們再來撰寫下測驗代碼:
// 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);
}
}
運行結果:

接下來,是最有意思的部分,我們來分析下代碼中new的時候發生了什么,
new操作的程序
當我們new一個物件的時候JVM首先會去找到對應的類元資訊,如果找不到意味著類資訊還沒有被加載,所以在物件創建的時候也可能會觸發類的加載操作,當類元資訊被加載之后,我們就可以通過類元資訊來確定物件資訊和需要申請的記憶體大小,
物件創建的流程
1.構建物件
首先main執行緒會在堆疊中申請一個屬于自己的堆疊空間,然后我們呼叫main方法的時候,會生成一個main方法的堆疊幀,然后執行new Man(),這里會根據Man類的元資訊先確定物件的大小,然后在JVM堆里申請一塊記憶體區域并構建物件,同時對Man物件成員變數資訊
并賦予默認值(在這里會涉及多型,在記憶體中的分配情況有機會再解釋解釋),

2.初始化物件
這一步會執行物件內部的init方法,初始化成員變數值,即執行物件的構造方法(這里呼叫父類的構造方法進行賦值),構造方法執行完,此時的age = 21,name = "codevald",

3.參考物件
物件實體化完成之后,再把堆疊中的Person物件參考地址指向Man物件在堆記憶體中的地址

4.繼續構造、初始化,參考物件物件
這一步和上面三個步驟一樣,就不詳細說了
附上圖



5.呼叫方法
呼叫speak()方法的時候,會先找到Person物件(codevald)中的參考地址,找到真正的在堆記憶體中的Man物件,執行speak()方法,執行的時候,會呼叫父類中的成員變數,所以會找到堆記憶體中的父物件的成員變數(name和age),加載進來,進行輸出
`我的名字是: codevald
我今年21歲了.`

呼叫sayInfo()方法的時候,一樣先找到物件(codevald)中的參考地址,找到真正的在堆記憶體中的Man物件,執行sayInfo()方法,執行的時候,會找到Person物件(linyuner)的地址,即指向堆記憶體中的Woman物件,找到父類里面的成員變數(name和age),進行輸出
`我的女朋友是:linyuer
她今年20歲了.`

下面的代碼的執行程序同理,就留給小伙伴們自行去分析啦~
附上TestPerson的位元組碼檔案,感興趣的小伙伴可以自行查看進行分析
Compiled from "TestPerson.java"
public class person.TestPerson {
public person.TestPerson();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #7 // class person/Man
3: dup
4: bipush 21
6: ldc #9 // String codevald
8: invokespecial #11 // Method person/Man."<init>":(ILjava/lang/String;)V
11: astore_1
12: new #14 // class person/Woman
15: dup
16: bipush 20
18: ldc #16 // String linyuer
20: invokespecial #18 // Method person/Woman."<init>":(ILjava/lang/String;)V
23: astore_2
24: aload_1
25: invokevirtual #19 // Method person/Person.speak:()V
28: aload_1
29: aload_2
30: invokevirtual #24 // Method person/Person.sayInfo:(Lperson/Person;)V
33: aload_2
34: invokevirtual #19 // Method person/Person.speak:()V
37: aload_2
38: aload_1
39: invokevirtual #24 // Method person/Person.sayInfo:(Lperson/Person;)V
42: return
}
學無止境,我們曾經擅長的正在被淘汰,不擅長的卻是仍然存在,最基礎的往往是最難的,而往往也是最重要的,平時注重基礎的積累,學會去分析底層的執行程序,才是學習中最應該掌握的技能,希望這篇回答能幫到正在尋找這個問題的答案的你~
如果覺得這篇文章不錯的話,記得幫我@codevald點個贊喲,感謝您的支持!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/255539.html
標籤:面向對象
