java繼承與合成基本概念
繼承:可以基於已經存在的類別來建構一個新類別。繼承已經存在的類別就可以重複使用這些類別的方法和域。在此基礎上,可以新增新的方法和域,從而擴充了類別的功能。
合成:在新類別裡創造原有的物件稱為合成。這種方式可以重複利用現有的程式碼而不更改它的形式。
相關影片教學推薦:java影片教學
1.繼承的語法
關鍵字extends表示新類別衍生於一個已經存在的類別。已存在的類別稱為父類別或基底類別,新類別稱為子類別或衍生類別。例如:
class Student extends Person { }
類別Student繼承了Person,Person類別稱為父類別或基底類,Student類別稱為子類別或衍生類別。
2.合成的語法
合成比較簡單,就是在一個類別中創建一個已經存在的類別。
class Student { Dog dog; }
上溯造型
#1.基本概念
##繼承的作用在於程式碼的複用。由於繼承意味著所有父類別的方法亦可在子類別中使用,所以發給父類別的訊息亦可發給衍生類別。如果Person類別中有一個eat方法,那麼Student類別中也會有這個方法,這表示Student物件也是Person的一種型別。class Person { public void eat() { System.out.println("eat"); } static void show(Person p) { p.eat(); } } public class Student extends Person{ public static void main(String[] args) { Student s = new Student(); Person.show(s); // ① } }【運行結果】:
eat
2.為什麼要上溯造型
為什麼在呼叫eat是要有意忽略呼叫它的物件型別呢?如果讓show方法簡單地取得Student句柄似乎更直觀易懂,但是那樣會使衍生自Person類別的每一個新類別都要實現專屬自己的show方法:class Value { private int count = 1; private Value(int count) { this.count = count; } public static final Value v1 = new Value(1), v2 = new Value(2), v3 = new Value(3); } class Person { public void eat(Value v) { System.out.println("Person.eat()"); } } class Teacher extends Person { public void eat(Value v) { System.out.println("Teacher.eat()"); } } class Student extends Person { public void eat(Value v) { System.out.println("Student.eat()"); } } public class UpcastingDemo { public static void show(Student s) { s.eat(Value.v1); } public static void show(Teacher t) { t.eat(Value.v1); } public static void show(Person p) { p.eat(Value.v1); } public static void main(String[] args) { Student s = new Student(); Teacher t = new Teacher(); Person p = new Person(); show(s); show(t); show(p); } }這種做法一個很明顯的缺陷就是必須為每一個Person類別的衍生類別定義與之緊密相關的方法,產生了許多重複的程式碼。另一方面,對於如果忘記了方法的重載也不會報錯。上例中的三個show方法完全可以合併為一個:
public static void show(Person p) { p.eat(Value.v1); }
動態綁定
當執行show(s)時,輸出結果是Student.eat(),這確實是希望得到的結果,但是似乎沒有按照我們希望的形式來執行,再來看一下show方法:public static void show(Person p) { p.eat(Value.v1); }它接收的是Person句柄,當執行show(s)時,它是如何知道Person句柄指向的是一個Student物件而不是Teacher物件呢?編譯器是無從得知的,這牽涉到接下來要說明的綁定問題。
1.方法呼叫的綁定
將一個方法同一個方法主體連接在一起就稱為綁定(Binding)。若在運行運行前執行綁定,就稱為「早期綁定」。上面的例子中,在只有一個Person句柄的情況下,編譯器不知道要具體地呼叫哪個方法。 Java實作了一種方法呼叫機制,可在運行期間判斷物件的類型,然後呼叫對應的方法,這種方法在運行期間進行,以物件的類型為基礎的綁定稱為動態綁定。除非一個方法被宣告為final,Java中的所有方法都是動態綁定的。 用一張圖表示上溯造型的繼承關係:Shape s = new Shape();依照繼承關係,將創建的Circle物件句柄賦給一個Shape是合法的,因為Circle屬於Shape的一種。 當呼叫其中一個基礎類別方法時:
Shape s = new Shape();此時,呼叫的是Circle.draw(),這是由於動態綁定的原因。
class Person { void eat() {} void speak() {} } class Boy extends Person { void eat() { System.out.println("Boy.eat()"); } void speak() { System.out.println("Boy.speak()"); } } class Girl extends Person { void eat() { System.out.println("Girl.eat()"); } void speak() { System.out.println("Girl.speak()"); } } public class Persons { public static Person randPerson() { switch ((int)(Math.random() * 2)) { default: case 0: return new Boy(); case 1: return new Girl(); } } public static void main(String[] args) { Person[] p = new Person[4]; for (int i = 0; i < p.length; i++) { p[i] = randPerson(); // 随机生成Boy或Girl } for (int i = 0; i < p.length; i++) { p[i].eat(); } } }對所有從Person衍生出來的類,Person建立了一個通用接口,所有衍生的類都有eat和speak兩種行為。衍生類別涵蓋了這些定義,重新定義了這兩種行為。 在主類別中,randPerson隨機選擇Person物件的句柄。 **上訴造型是在return語句裡發生的。 **return語句取得一個Boy或Girl的句柄並將其作為Person類型傳回,此時並不知道具體是什麼類型,只知道是Person物件句柄。 在main方法中呼叫randPerson方法為數組填入Person對象,但不知具體情況。當呼叫數組每個元素的eat方法時,動態綁定的作用就是執行物件的重新定義了的方法。 然而,動態綁定是有前提的,綁定的方法必須存在於基底類別中,否則無法編譯通過。
class Person { void eat() { System.out.println("Person.eat()"); } } class Boy extends Person { void eat() { System.out.println("Boy.eat()"); } void speak() { System.out.println("Boy.speak()"); } } public class Persons { public static void main(String[] args) { Person p = new Boy(); p.eat(); p.speak(); // The method speak() is undefined for the type Person } }
如果子类中没有定义覆盖方法,则会调用父类中的方法:
class Person { void eat() { System.out.println("Person.eat()"); } } class Boy extends Person { } public class Persons { public static void main(String[] args) { Person p = new Boy(); p.eat(); } }
【运行结果】:
Person.eat()
2.静态方法的绑定
将上面的方法都加上static关键字,变成静态方法:
class Person { static void eat() { System.out.println("Person.eat()"); } static void speak() { System.out.println("Person.speak()"); } } class Boy extends Person { static void eat() { System.out.println("Boy.eat()"); } static void speak() { System.out.println("Boy.speak()"); } } class Girl extends Person { static void eat() { System.out.println("Girl.eat()"); } static void speak() { System.out.println("Girl.speak()"); } } public class Persons { public static Person randPerson() { switch ((int)(Math.random() * 2)) { default: case 0: return new Boy(); case 1: return new Girl(); } } public static void main(String[] args) { Person[] p = new Person[4]; for (int i = 0; i < p.length; i++) { p[i] = randPerson(); // 随机生成Boy或Girl } for (int i = 0; i < p.length; i++) { p[i].eat(); } } }
【运行结果】:
Person.eat() Person.eat() Person.eat() Person.eat()
观察结果,对于静态方法而言,不管父类引用指向的什么子类对象,调用的都是父类的方法。
更多java相关文章请关注java基础教程栏目。
以上是Java中繼承圖文詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 Linux新版
SublimeText3 Linux最新版

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

WebStorm Mac版
好用的JavaScript開發工具