Java基礎5——深入理解抽象類和介面
抽象類和介面
抽象方法和抽象類
抽象方法是一種特殊的方法:它只有宣告,而沒有具體的實現。抽象方法的宣告格式為:
abstract void f();
《Java程式設計思想》一書中將抽象類定義為包含抽象方法的類,但準確來說,包含抽象方法的類一定是抽象類,但抽象類不 一定有抽象方法,只要用abstract修飾即可為抽象類。(不必糾結具體的概念)
[public] abstract class Instrument{
abstract void f();
}
抽象類是對類(一類事物)的抽象, 抽象類就是為了繼承而存在的。它和普通類一樣,同樣可以擁有成員變數和普通的成員方法
-
抽象方法必須為public或 protected的,預設情況下預設為public,因為抽象方法需要被子類繼承和實現。
-
抽象類不能用來建立物件
-
如果一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。
介面
在Java中,定一個介面的形式如下:
[public] interface InterfaceName {
}
介面是對行為的抽象,其可以含有屬性和方法。屬性被隱式指定為public static final的,即全域性常量。(並且只能是public static final變數,用private修飾會報編譯錯誤
從這裡可以隱約看出介面和抽象類的區別,介面是一種極度抽象的型別,它比抽象類更加“抽象”,並且一般情況下不在介面中定義變數。
要讓一個類遵循某組特地的介面需要使用implements關鍵字,具體格式如下:
class ClassName implements Interface1,Interface2,[....]{
}
允許一個類遵循多個特定的介面。如果一個非抽象類遵循了某個介面,就必須實現該介面中的所有方法。對於遵循某個介面的抽象類,可以不實現該介面中的抽象方法
抽象類和介面的區別
語法層面上的區別
- 成員變數:抽象類中的成員變數可以是各種型別的,而介面中的成員變數只 能是常量,即public static final修飾的。
- 成員方法:抽象類中的成員方法可以是抽象的也可以是普通的(有具體實現 的),而介面中的成員方法只能是public static修飾的。
- 靜態結構:抽象類中可以有靜態程式碼塊和靜態方法,而介面中不能有靜態代 碼塊和靜態方法。
- 靜態結構:抽象類中可以有靜態程式碼塊和靜態方法,而介面中不能有靜態代 碼塊和靜態方法。
- 構造方法:抽象類中可以有構造器,而介面中沒有,但兩者都不能進行例項化,但可以定義抽象類和介面型別的引用。
- 繼承與實現:一個類只能繼承一個抽象類,而一個類卻可以實現多個介面。
設計層面上的區別
- 抽象類是對類(一類事物)的抽象,而介面是對行為的抽象。再具體一點說,抽象類是對一類事物整體(包括屬性和行為)進行抽象,而介面是對類 的區域性(僅對行為)進行抽象。如飛機、鳥和飛行而言,應分別將其設計為 類、類和介面。
- 抽象類作為很多子類的父類,是一種模板式設計,而介面作為一種行為規範,是一種輻射式設計。如果需要新增新的方法,抽象類作為模板,可以直接新增帶具體實現的方法而無需改變子類,而介面作為規範,規範改變(新增行為),遵守規範的子類都必須進行相應的改動。
抽象類和介面的應用場景
問題:「你在專案中哪些地方使用過介面和抽象類?具體是怎麼使用的?」
分析:門都有開啟和關閉兩個行為,此時若需要門具備警報行為,應該如何實現呢?
其實,門的開啟和關閉屬於門本身固有的行為,而警報功能屬於門非固有的行為 (附加行為)。最佳解決方案是,將門設計為一個抽象類,包括開啟和關閉兩種 行為,而將警報設計為一個介面,包括警報行為,進而設計一個警報門繼承抽象 類並實現警報介面即可。
參考部落格:新增連結描述
門和警報的例子:門都有 open( )和 close( )兩個動作,此時我們可以定義通過抽象類和介面來定義這個抽象概念:
abstract class Door {
public abstract void open();
public abstract void close();
}
interface Door {
public abstract void open();
public abstract void close();
}
*但是現在如果我們需要門具有報警 alarm( )的功能,那麼該如何實現?下面提供兩種思路:
1)將這三個功能都放在抽象類裡面,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是有的門並不一定具備報警功能;
2)將這三個功能都放在接口裡面,需要用到報警功能的類就需要實現這個介面中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。
從這裡可以看出, Door的 open() 、close()和 alarm()根本就屬於兩個不同範疇內的行為,open()和close()屬於門本身固有的行為特性,而alarm()屬於延伸的附加行為。因此最好的解決辦法是單獨將報警設計為一個介面,包含 alarm()行為, Door設計為單獨的一個抽象類,包含 open和 close兩種行為。再設計一個報警門繼承 Door類和實現 Alarm介面。
interface Alram {
void alarm();
}
abstract class Door {
void open();
void close();
}
class AlarmDoor extends Door implements Alarm {
void oepn() {
//....
}
void close() {
//....
}
void alarm() {
//....
}
}
小的細節
class A {
}
interface M extends N,L{//正確的,不會報錯;介面可以繼承多個其他的介面
}
interface N{
}
interface L{
}
interface 介面 {
public final int i = 1;//變數預設都為public final修飾
final A a = null;//基本資料型別和引用都一樣
//protected void a();//報錯
//private //報錯
public abstract void a();// 方法都是public abstract修飾的。
//void b(){} 報錯,接口裡的方法不能有方法體,也不能有{},只能有();
// final void b();
// 注意,抽象方法不能加final。因為final方法不能被重寫。
//但如果抽象方法不被重寫那就沒有意義了,因為他根本沒有程式碼體。
}
abstract class 抽象類 {
public final int i = 1;//變數並沒有被pulic和final修飾,只是一般的成員變數
public final A a = null;
private void A(){}//抽象類可以有具體方法
abstract void AA();//抽象方法沒有方法體
//private abstract void B();//報錯,組合非法
// 因為private修飾的方法無法被子類重寫,所以和final一樣,使抽象方法無法被實現。
}
//抽象類也可以被例項化,舉例說明
abstract class B{
B() {
System.out.println("b init");
}
}
class C extends B{
C(){
super();
System.out.println("c init");
}
}
public class 介面對比抽象類 {
@Test
public void test() {
C c = new C();
//結果先例項化B,再例項化C。
//因為會呼叫到父類的構造方法。
}
}
---------------------
作者:How 2 Play Life
來源:CSDN
原文:https://blog.csdn.net/a724888/article/details/80061047
版權宣告:本文為博主原創文章,轉載請附上博文連結!