版權聲明:本文由吳仙傑創做整理,轉載請註明出處:http://www.javashuo.com/article/p-olibxwhm-er.htmljava
Java 面向對象編程有三大特性:封裝、繼承、多態。面試
封裝
: 隱藏對象的屬性和實現細節,僅對外公開訪問方法,控制在程序中屬性的讀和寫的訪問級別。shell
加強安全性和簡化編程,使用者沒必要了解具體的實現細節,而只要經過對外公開的訪問方法,來使用類的成員。編程
把全部的屬性私有化。segmentfault
對每一個屬性提供 getter
和 setter
方法。安全
若是有一個帶參的構造函數的話,那必定要寫一個不帶參的構造函數。函數
建議重寫 toString
方法,但這不是必須的。測試
繼承
: 能夠理解爲,在一個現有類的基礎之上,增長新的方法或重寫已有方法,從而產生一個新類。.net
咱們在編寫 Java 代碼時,每個類都是在繼承。由於在 Java 中存在一個全部類的父類(基類、超類):java.lang.Object
。code
子類不能繼承父類中訪問權限爲 private
的成員變量和方法,也不能繼承父類的構造方法。子類能夠重寫父類的方法,及命名與父類同名的成員變量。
有時候咱們會有這樣的需求:咱們須要將某些事物儘量地對這個世界隱藏,可是仍然容許子類的成員來訪問它們。這個時候就須要使用到 protected
。
類成員訪問修飾符與訪問能力之間的關係:
類型 | private | 無修飾 | protected | public |
---|---|---|---|---|
同一類 | 可訪問 | 可訪問 | 可訪問 | 可訪問 |
同一包中的子類 | 不可訪問 | 可訪問 | 可訪問 | 可訪問 |
同一包中的非子類 | 不可訪問 | 可訪問 | 可訪問 | 可訪問 |
不一樣包中的子類 | 不可訪問 | 不可訪問 | 可訪問 | 可訪問 |
不一樣包中的非子類 | 不可訪問 | 不可訪問 | 不可訪問 | 可訪問 |
Java 中類可分爲如下三種:
普通類:使用 class
定義且不含有抽象方法的類。
抽象類:使用 abstract class
定義的類,它能夠含有或不含有抽象方法。
接口:使用 interface
定義的類。
上述三種類存在如下的繼承規律:
普通類能夠繼承(extends
)普通類,能夠繼承(extends
)抽象類,能夠繼承(implements
)接口。
抽象類能夠繼承(extends
)普通類,能夠繼承(extends
)抽象類,能夠繼承(implements
)接口。
接口只能繼承(extends
)接口。
注意:
上述的繼承規律中,每種繼承都有各自使用的關鍵字 extends
和 implements
,不可混淆使用。
上述描述中,咱們沒有對 implements
關鍵字使用實現這種說法,是由於從概念上來說,它也是一種繼承關係,並且對於抽象類 implements
接口而言,它並不要求必定要實現這個接口中定義的方法。
各繼承規律中的約束:
一個普通類或一個抽象類,要麼繼承一個普通類,要麼繼承一個抽象類,即所謂的單繼承。
一個普通類或一個抽象類或一個接口,能夠繼承任意多個接口。
一個普通類繼承一個抽象類後,必須實現這個抽象類中定義的全部抽象(abstract
)方法,不然就只能被定義爲抽象類。
一個普通類繼承一個接口後,必須實現這個接口中定義的全部方法,不然就只能被定義爲抽象類。
抽象類繼承抽象類,或者實現接口時,能夠部分、所有或者徹底不實現父類抽象類的抽象(abstract
)方法或父類接口中定義的方法。
繼承給咱們的編程帶來的好處就是對原有類的複用(重用)。除了繼承以外,咱們還可使用組合的方式來複用類。
所謂組合就是把原有類定義爲新類的一個屬性,經過在新類中調用原有類的方法來實現複用。從抽象概念上來說,新定義類所表明的事物是原有類所表明的事物的一種,那麼這時組合就是實現複用更好的選擇。下面這個例子就是組合方式的一個簡單示例:
/** * 寶馬 */ public class BMW { private Car car = new Car(); public void driveBMW() { // 複用汽車類的通用駕駛方法 car.drive(); // 再寫寶馬車的特定駕駛方法 } } /** * 汽車 */ class Car { public void drive() { // 開車 } }
使用繼承和組合複用原有的類,都是一種增量式的開發模式,這種方式帶來的好處是不須要修改原有的代碼,所以不會給原有代碼帶來新的 BUG,也不用由於對原有代碼的修改而從新進行測試,這對咱們的開發顯然是有益的。所以,若是咱們是在維護或者改造一個原有的系統或模塊,尤爲是對它們的瞭解不是很透徹的時候,就能夠選擇增量開發的模式,這不只能夠大大提升咱們的開發效率,也能夠規避因爲對原有代碼的修改而帶來的風險。
多態
: 相同的事物,調用其相同的方法,參數也相同時,但表現的行爲卻不一樣。
如下的例子,可幫助理解:
/** * 汽車接口 */ interface Car { // 汽車名稱 String getName(); // 得到汽車售價 int getPrice(); } // 寶馬 class BMW implements Car { public String getName() { return "BMW"; } public int getPrice() { return 300000; } } // 奔馳 class BENZ implements Car { public String getName() { return "BENZ"; } public int getPrice() { return 400000; } } // 汽車出售店 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() { return money; } public static void main(String[] args) { CarShop carShop = new CarShop(); // 賣出一輛寶馬 carShop.sellCar(new BMW()); // 賣出一輛奔馳 carShop.sellCar(new BENZ()); System.out.println("總收入:" + carShop.getMoney()); } }
運行結果:
車型:BMW 單價:300000 車型:BENZ 單價:400000 總收入:700000
繼承是多態得以實現的基礎。針對上面的示例,多態就是一種類型(都是 Car
類型)表現出多種狀態(寶馬汽車的名稱是 BMW,售價是 300000;奔馳汽車的名稱是 BENZ,售價是 400000)。
綁定
: 將一個方法調用同這個方法所屬的主體(也就是對象或類)關聯起來,分前期綁定和後期綁定兩種。
前期綁定:在程序運行以前進行綁定,由編譯器和鏈接程序實現,又叫作靜態綁定。好比
static
方法和final
方法,注意,這裏也包括private
方法,由於它是隱式final
的。後期綁定:在運行時根據對象的類型進行綁定,由方法調用機制實現,所以又叫作動態綁定,或者運行時綁定。除了前期綁定外的全部方法都屬於後期綁定。
多態就是在後期綁定這種機制上實現的。
多態給咱們帶來的好處是消除了類之間的耦合關係,使程序更容易擴展。好比在上例中,新增長一種類型汽車的銷售,只須要讓新定義的類繼承 Car
類並實現它的全部方法,而無需對原有代碼作任何修改,CarShop
類的 sellCar(Car car)
方法就能夠處理新的車型了。
繼承:在多態中必須存在有繼承關係的子類和父類。
重寫:子類對父類中某些方法進行從新定義,在調用這些方法時就會調用子類的方法。
向上轉型:在多態中須要將子類的引用賦給父類對象,只有這樣該引用纔可以具有技能調用父類的方法和子類的方法。
只有知足了上述三個條件,咱們纔可以在同一個繼承結構中使用統一的邏輯實現代碼處理不一樣的對象,從而達到執行不一樣的行爲。
基於繼承實現的多態
: 主要表如今父類和繼承該父類的一個或多個子類對某些方法的重寫,多個子類對同一方法的重寫能夠表現出不一樣的行爲。
基於接口實現的多態
: 在接口的多態中,指向接口的引用必須是指定這實現了該接口的一個類的實例,在運行時,根據對象引用的實際類型來執行對應的方法。
繼承都是單繼承,只能爲一組相關的類提供一致的服務接口。
接口是多繼承多實現,它可以利用一組相關或者不相關的接口進行組合與擴充,可以對外提供一致的服務接口。因此它相對於繼承來講有更好的靈活性。
重載和重寫都是針對方法的概念,在弄清楚這兩個概念以前,咱們先來了解一下什麼叫方法的型構(signature)。
型構
: 指方法的組成結構,具體包括方法的名稱和參數,涵蓋參數的數量、類型以及出現的順序,可是不包括方法的返回值類型,訪問權限修飾符,以及 abstract、static、final 等修飾符。
示例1、下面兩個是具備相同型構的方法:
public void method(int i, String s) { // do something } public String method(int i, String s) { // do something }
注意:在同一個類中,是不容許定義多於一個的具備相同型構的方法。
示例2、下面兩個是具備不一樣型構的方法:
public void method(int i, String s) { // do something } public void method(String s, int i) { // do something }
瞭解完型構的概念後咱們再來看看重載和重寫:
重寫(overriding)
: 指在繼承狀況下,子類中定義了與其父類中方法具備相同型構的新方法,就稱爲子類把父類的方法重寫了。這是實現多態必須的步驟。
重載(overloading)
: 指在同一個類中定義了一個以上具備相同名稱,可是型構不一樣的方法。
爲了加深理解,咱們來考慮一個有趣的問題:構造器能夠被重載嗎?
答案固然是能夠的,咱們在實際的編程中也常常這麼作。實際上構造器也是一個方法,構造器名就是方法名,構造器參數就是方法參數,而它的返回值就是新建立的類的實例。可是構造器卻不能夠被子類重寫,由於子類沒法定義與父類具備相同型構的構造器。