JAVA面試題解惑系列(九)——繼承、多態、重載和重寫

來源:互聯網
上載者:User

什麼是多態?它的實現機制是什麼呢?重載和重寫的區別在那裡?這就是這一次我們要回顧的四個十分重要的概念:繼承、多態、重載和重寫。

繼承

簡單的說,繼承就是在一個現有類型的基礎上,通過增加新的方法或者重定義已有方法(下面會講到,這種方式叫重寫)的方式,產生一個新的類型。繼承是物件導向的三個基本特徵--封裝、繼承、多態的其中之一,我們在使用JAVA時編寫的每一個類都是在繼承,因為在JAVA語言中,java.lang.Object類是所有類最根本的基類(或者叫父類、超類),如果我們新定義的一個類沒有明確地指定繼承自哪個基類,那麼JAVA 就會預設為它是繼承自Object類的。

我們可以把JAVA中的類分為以下三種:

1. 普通類:使用class定義且不含有抽象方法的類。
2. 抽象類別:使用abstract class定義的類,它可以含有,也可以不含有抽象方法。
3. 介面類:使用interface定義的類。

在這三種類型之間存在下面的繼承規律:

* 普通類可以繼承(extends)普通類,可以繼承(extends)抽象類別,可以繼承(implements)介面。
* 抽象類別可以繼承(extends)普通類,可以繼承(extends)抽象類別,可以繼承(implements)介面。
* 介面只能繼承(extends)介面。

請注意上面三條規律中每種繼承情況下使用的不同的關鍵字extends和implements,它們是不可以隨意替換的。大家知道,一個普通類繼承一個介面後,必須這個介面中定義的所有方法,否則就只能被定義為抽象類別。我在這裡之所以沒有對implements關鍵字使用“實現”這種說法是因為從概念上來說它也是表示一種繼承關係,而且對於抽象類別implements介面的情況下,它並不是一定要實現這個介面定義的任何方法,因此使用繼承的說法更為合理一些。

以上三條規律同時遵守下面這些約束:

1. 普通類和抽象類別都只能最多繼承一個普通類,或者最多繼承一個抽象類別,並且這兩種情況是互斥的,也就是說它們要麼繼承一個普通類,要麼繼承一個抽象類別。
2. 普通類、抽象類別和介面在繼承介面時,不受數量的約束,理論上可以繼承無限多個介面。當然,對於普通類來說,它必須實現它所繼承的所有介面中定義的全部方法。

繼承給我們的編程帶來的好處就是對原有類的複用(重用)。就像模組的複用一樣,類的複用可以提高我們的開發效率,實際上,模組的複用是大量類的複用疊加後的效果。除了繼承之外,我們還可以使用組合的方式來複用類。所謂組合就是把原有類定義為新類的一個屬性,通過在新類中調用原有類的方法來實現複用。如果新定義的類型與原有類型之間不存在被包含的關係,也就是說,從抽象概念上來講,新定義類型所代表的事物並不是原有類型所代表事物的一種,比如黃種人是人類的一種,它們之間存在包含與被包含的關係,那麼這時組合就是實現複用更好的選擇。下面這個例子就是組合方式的一個簡單樣本:
Java代碼 複製代碼

1. public class Sub {
2. private Parent p = new Parent();
3.
4. public void doSomething() {
5. // 複用Parent類的方法
6. p.method();
7. // other code
8. }
9. }
10.
11. class Parent {
12. public void method() {
13. // do something here
14. }
15. }

當然,為了使代碼更加有效,我們也可以在需要使用到原有類型(比如Parent p)時,才對它進行初始化。

使用繼承和組合複用原有的類,都是一種增量式的開發模式,這種方式帶來的好處是不需要修改原有的代碼,因此不會給原有代碼帶來新的BUG,也不用因為對原有代碼的修改而重新進行測試,這對我們的開發顯然是有益的。因此,如果我們是在維護或者改造一個原有的系統或模組,尤其是對它們的瞭解不是很透徹的時候,就可以選擇漸進式開發的模式,這不僅可以大大提高我們的開發效率,也可以規避由於對原有代碼的修改而帶來的風險。

多態

多態是又一個重要的基本概念,上面說到了,它是物件導向的三個基本特徵之一。究竟什麼是多態呢?我們先看看下面的例子,來協助理解:
Java代碼 複製代碼

1. //汽車介面
2. interface Car {
3. // 汽車名稱
4. String getName();
5.
6. // 獲得汽車售價
7. int getPrice();
8. }
9.
10. // 寶馬
11. class BMW implements Car {
12. public String getName() {
13. return "BMW";
14. }
15.
16. public int getPrice() {
17. return 300000;
18. }
19. }
20.
21. // 奇瑞QQ
22. class CheryQQ implements Car {
23. public String getName() {
24. return "CheryQQ";
25. }
26.
27. public int getPrice() {
28. return 20000;
29. }
30. }
31.
32. // 汽車出售店
33. public class CarShop {
34. // 售車收入
35. private int money = 0;
36.
37. // 賣出一部車
38. public void sellCar(Car car) {
39. System.out.println("車型:" + car.getName() + " 單價:" + car.getPrice());
40. // 增加賣出車售價的收入
41. money += car.getPrice();
42. }
43.
44. // 售車總收入
45. public int getMoney() {
46. return money;
47. }
48.
49. public static void main(String[] args) {
50. CarShop aShop = new CarShop();
51. // 賣出一輛寶馬
52. aShop.sellCar(new BMW());
53. // 賣出一輛奇瑞QQ
54. aShop.sellCar(new CheryQQ());
55. System.out.println("總收入:" + aShop.getMoney());
56. }
57. }

運行結果:

1. 車型:BMW 單價:300000
2. 車型:CheryQQ 單價:20000
3. 總收入:320000

繼承是多態得以實現的基礎。從字面上理解,多態就是一種類型(都是Car類型)表現出多種狀態(寶馬汽車的名稱是BMW,售價是300000;奇瑞汽車的名稱是CheryQQ,售價是2000)。將一個方法調用同這個方法所屬的主體(也就是對象或類)關聯起來叫做綁定,分前期綁定和後期綁定兩種。下面解釋一下它們的定義:

1. 前期綁定:在程式運行之前進行綁定,由編譯器和串連程式實現,又叫做靜態繫結。比如static方法和final方法,注意,這裡也包括private方法,因為它是隱式final的。
2. 後期綁定:在運行時根據對象的類型進行綁定,由方法調用機制實現,因此又叫做動態綁定,或者運行時綁定。除了前期綁定外的所有方法都屬於後期綁定。

多態就是在後期綁定這種機制上實現的。多態給我們帶來的好處是消除了類之間的耦合關係,使程式更容易擴充。比如在上例中,新增加一種類型汽車的銷售,只需要讓新定義的類繼承Car類並實現它的所有方法,而無需對原有代碼做任何修改,CarShop類的sellCar(Car car)方法就可以處理新的車型了。新增代碼如下:
Java代碼 複製代碼

1. // 桑塔納汽車
2. class Santana implements Car {
3. public String getName() {
4. return "Santana";
5. }
6.
7. public int getPrice() {
8. return 80000;
9. }
10. }

重載和重寫

重載和重寫都是針對方法的概念,在弄清楚這兩個概念之前,我們先來瞭解一下什麼叫方法的型構。型構就是指方法的組成結構,具體包括方法的名稱和參數,涵蓋參數的數量、類型以及出現的順序,但是不包括方法的傳回值類型,存取權限修飾符,以及abstract、static、final等修飾符。比如下面兩個就是具有相同型構的方法:
Java代碼 複製代碼

1. public void method(int i, String s) {
2. // do something
3. }
4.
5. public String method(int i, String s) {
6. // do something
7. }

而這兩個就是具有不同型構的方法:
Java代碼 複製代碼

1. public void method(int i, String s) {
2. // do something
3. }
4.
5. public void method(String s, int i) {
6. // do something
7. }

瞭解完型構的概念後我們再來看看重載和重寫,請看它們的定義:

* 重寫,英文名是override,是指在繼承情況下,子類中定義了與其基類中方法具有相同型構的新方法,就叫做子類把基類的方法重載了。這是實現多態必須的步驟。
* 重載,英文名是overload,是指在同一個類中定義了一個以上具有相同名稱,但是型構不同的方法。在同一個類中,是不允許定義多於一個的具有相同型構的方法的。

我們來考慮一個有趣的問題:構造器可以被重載嗎?答案當然是可以的,我們在實際的編程中也經常這麼做。實際上構造器也是一個方法,構造器名就是方法名,構造器參數就是方法參數,而它的傳回值就是新建立的類的執行個體。但是構造器卻不可以被子類重寫,因為子類無法定義與基類具有相同型構的構造器。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.