繼承、多型,過載、重寫的區別與總…
阿新 • • 發佈:2018-12-30
繼承、多型,過載、重寫的區別與總結
一道必考的JAVA核心面試題,什麼是多型?它的實現機制是什麼呢?過載和重寫的區別在那裡?這就是這一次我們要回顧的四個十分重要的概念:繼承、多型、過載和重寫。
繼承(inheritance)
簡單的說,繼承就是在一個現有型別的基礎上,通過增加新的方法或者重定義已有方法(下面會講到,這種方式叫重寫)的方式,產生一個新的型別。繼承是面向物件的三個基本特徵--封裝、繼承、多型的其中之一,我們在使用JAVA時編寫的每一個類都是在繼承,因為在JAVA語言中,java.lang.Object類是所有類最根本的基類(或者叫父類、超類),如果我們新定義的一個類沒有明確地指定繼承自哪個基類,那麼JAVA就會預設為它是繼承自Object類的。
我們可以把JAVA中的類分為以下三種:
類:使用class定義且不含有抽象方法的類。
抽象類:使用abstract class定義的類,它可以含有也可以不含有抽象方法。
介面:使用interface定義的類。
在這三種類型之間存在下面的繼承規律:
類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
抽象類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
介面只能繼承(extends)介面。
請注意上面三條規律中每種繼承情況下使用的不同的關鍵字extends和implements,它們是不可以隨意替換的。大家知道,一個普通類繼承一個介面後,必須實現這個介面中定義的所有方法,否則就只能被定義為抽象類。我在這裡之所以沒有對implements關鍵字使用“實現”這種說法是因為從概念上來說它也是表示一種繼承關係,而且對於抽象類implements介面的情況下,它並不是一定要實現這個介面定義的任何方法,因此使用繼承的說法更為合理一些。
以上三條規律同時遵守下面這些約束:
類和抽象類都只能最多繼承一個類,或者最多繼承一個抽象類,並且這兩種情況是互斥的,也就是說它們要麼繼承一個類,要麼繼承一個抽象類。
類、抽象類和介面在繼承介面時,不受數量的約束,理論上可以繼承無限多個介面。當然,對於類來說,它必須實現它所繼承的所有介面中定義的全部方法。
抽象類繼承抽象類,或者實現介面時,可以部分、全部或者完全不實現父類抽象類的抽象(abstract)方法,或者父類介面中定義的介面。
類繼承抽象類,或者實現介面時,必須全部實現父類抽象類的全部抽象(abstract)方法,或者父類介面中定義的全部介面。
繼承給我們的程式設計帶來的好處就是對原有類的複用(重用)。就像模組的複用一樣,類的複用可以提高我們的開發效率,實際上,模組的複用是大量類的複用疊加後的效果。除了繼承之外,我們還可以使用組合的方式來複用類。所謂組合就是把原有類定義為新類的一個屬性,通過在新類中呼叫原有類的方法來實現複用。如果新定義的型別與原有型別之間不存在被包含的關係,也就是說,從抽象概念上來講,新定義型別所代表的事物並不是原有型別所代表事物的一種,比如黃種人是人類的一種,它們之間存在包含與被包含的關係,那麼這時組合就是實現複用更好的選擇。下面這個例子就是組合方式的一個簡單示例:
Java程式碼
public class Sub {
private Parent p = new Parent();
public void doSomething() {
// 複用Parent類的方法
p.method();
// other code
}
}
class Parent {
public void method() {
// do something here
}
}
public class Sub {
private Parent p = new Parent();
public void doSomething() {
// 複用Parent類的方法
p.method();
// other code
}
}
class Parent {
public void method() {
// do something here
}
}
當然,為了使程式碼更加有效,我們也可以在需要使用到原有型別(比如Parent p)時,才對它進行初始化。
使用繼承和組合複用原有的類,都是一種增量式的開發模式,這種方式帶來的好處是不需要修改原有的程式碼,因此不會給原有程式碼帶來新的BUG,也不用因為對原有程式碼的修改而重新進行測試,這對我們的開發顯然是有益的。因此,如果我們是在維護或者改造一個原有的系統或模組,尤其是對它們的瞭解不是很透徹的時候,就可以選擇增量開發的模式,這不僅可以大大提高我們的開發效率,也可以規避由於對原有程式碼的修改而帶來的風險。
多型(Polymorphism)
多型是又一個重要的基本概念,上面說到了,它是面向物件的三個基本特徵之一。究竟什麼是多型呢?我們先看看下面的例子,來幫助理解:
Java程式碼
//汽車介面
interface Car {
// 汽車名稱
String getName();
// 獲得汽車售價
int getPrice();
}
// 寶馬
class BMW implements Car {
public String getName() {
return "BMW";
}
public int getPrice() {
return 300000;
}
}
// 奇瑞QQ
class CheryQQ implements Car {
public String getName() {
return "CheryQQ";
}
public int getPrice() {
return 20000;
}
}
// 汽車出售店
public class CarShop {
// 售車收入
private int money = 0;
// 賣出一部車
public void sellCar(Car car) {
System.out.println("車型:" car.getName() " 單價:" car.getPrice());
// 增加賣出車售價的收入
money = car.getPrice();
}
// 售車總收入
public int getMoney() {
一道必考的JAVA核心面試題,什麼是多型?它的實現機制是什麼呢?過載和重寫的區別在那裡?這就是這一次我們要回顧的四個十分重要的概念:繼承、多型、過載和重寫。
繼承(inheritance)
簡單的說,繼承就是在一個現有型別的基礎上,通過增加新的方法或者重定義已有方法(下面會講到,這種方式叫重寫)的方式,產生一個新的型別。繼承是面向物件的三個基本特徵--封裝、繼承、多型的其中之一,我們在使用JAVA時編寫的每一個類都是在繼承,因為在JAVA語言中,java.lang.Object類是所有類最根本的基類(或者叫父類、超類),如果我們新定義的一個類沒有明確地指定繼承自哪個基類,那麼JAVA就會預設為它是繼承自Object類的。
我們可以把JAVA中的類分為以下三種:
類:使用class定義且不含有抽象方法的類。
抽象類:使用abstract class定義的類,它可以含有也可以不含有抽象方法。
介面:使用interface定義的類。
在這三種類型之間存在下面的繼承規律:
類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
抽象類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
介面只能繼承(extends)介面。
請注意上面三條規律中每種繼承情況下使用的不同的關鍵字extends和implements,它們是不可以隨意替換的。大家知道,一個普通類繼承一個介面後,必須實現這個介面中定義的所有方法,否則就只能被定義為抽象類。我在這裡之所以沒有對implements關鍵字使用“實現”這種說法是因為從概念上來說它也是表示一種繼承關係,而且對於抽象類implements介面的情況下,它並不是一定要實現這個介面定義的任何方法,因此使用繼承的說法更為合理一些。
以上三條規律同時遵守下面這些約束:
類和抽象類都只能最多繼承一個類,或者最多繼承一個抽象類,並且這兩種情況是互斥的,也就是說它們要麼繼承一個類,要麼繼承一個抽象類。
類、抽象類和介面在繼承介面時,不受數量的約束,理論上可以繼承無限多個介面。當然,對於類來說,它必須實現它所繼承的所有介面中定義的全部方法。
抽象類繼承抽象類,或者實現介面時,可以部分、全部或者完全不實現父類抽象類的抽象(abstract)方法,或者父類介面中定義的介面。
類繼承抽象類,或者實現介面時,必須全部實現父類抽象類的全部抽象(abstract)方法,或者父類介面中定義的全部介面。
繼承給我們的程式設計帶來的好處就是對原有類的複用(重用)。就像模組的複用一樣,類的複用可以提高我們的開發效率,實際上,模組的複用是大量類的複用疊加後的效果。除了繼承之外,我們還可以使用組合的方式來複用類。所謂組合就是把原有類定義為新類的一個屬性,通過在新類中呼叫原有類的方法來實現複用。如果新定義的型別與原有型別之間不存在被包含的關係,也就是說,從抽象概念上來講,新定義型別所代表的事物並不是原有型別所代表事物的一種,比如黃種人是人類的一種,它們之間存在包含與被包含的關係,那麼這時組合就是實現複用更好的選擇。下面這個例子就是組合方式的一個簡單示例:
Java程式碼
public class Sub {
private Parent p = new Parent();
public void doSomething() {
// 複用Parent類的方法
p.method();
// other code
}
}
class Parent {
public void method() {
// do something here
}
}
public class Sub {
private Parent p = new Parent();
public void doSomething() {
// 複用Parent類的方法
p.method();
// other code
}
}
class Parent {
public void method() {
// do something here
}
}
當然,為了使程式碼更加有效,我們也可以在需要使用到原有型別(比如Parent p)時,才對它進行初始化。
使用繼承和組合複用原有的類,都是一種增量式的開發模式,這種方式帶來的好處是不需要修改原有的程式碼,因此不會給原有程式碼帶來新的BUG,也不用因為對原有程式碼的修改而重新進行測試,這對我們的開發顯然是有益的。因此,如果我們是在維護或者改造一個原有的系統或模組,尤其是對它們的瞭解不是很透徹的時候,就可以選擇增量開發的模式,這不僅可以大大提高我們的開發效率,也可以規避由於對原有程式碼的修改而帶來的風險。
多型(Polymorphism)
多型是又一個重要的基本概念,上面說到了,它是面向物件的三個基本特徵之一。究竟什麼是多型呢?我們先看看下面的例子,來幫助理解:
Java程式碼
//汽車介面
interface Car {
// 汽車名稱
String getName();
// 獲得汽車售價
int getPrice();
}
// 寶馬
class BMW implements Car {
public String getName() {
return "BMW";
}
public int getPrice() {
return 300000;
}
}
// 奇瑞QQ
class CheryQQ implements Car {
public String getName() {
return "CheryQQ";
}
public int getPrice() {
return 20000;
}
}
// 汽車出售店
public class CarShop {
// 售車收入
private int money = 0;
// 賣出一部車
public void sellCar(Car car) {
System.out.println("車型:" car.getName() " 單價:" car.getPrice());
// 增加賣出車售價的收入
money = car.getPrice();
}
// 售車總收入
public int getMoney() {