抽象類和介面
1. 抽象類
1.1 概述
父類中的方法,被它的子類們重寫,子類各自的實現都不盡相同。那麼父類的方法宣告和方法主體,只有宣告還有意義,而方法主體則沒有存在的意義了。我們把沒有方法主體的方法稱為抽象方法。Java語法規定,包含抽象方法的類就是抽象類。
1.2 抽象方法和抽象類的定義格式
抽象方法定義格式:
修飾符 abstract 返回值型別 方法名 (引數列表);
//程式碼舉例
public abstract void run();
抽象類定義格式:
abstract class 類名字 {
}
//程式碼舉例
public abstract class Animal {
public abstract void run();
}
1.3 使用抽象類的注意事項
1.抽象類不能建立物件,如果建立,編譯無法通過而報錯。只能建立其非抽象子類的物件。
理解:假設建立了抽象類的物件,呼叫抽象的方法,而抽象方法沒有具體的方法體,沒有意義。
2.抽象類中,可以有構造方法,是供子類建立物件時,初始化父類成員使用的。
理解:子類的構造方法中,有預設的super(),需要訪問父類構造方法。
3.抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
理解:未包含抽象方法的抽象類,目的就是不想讓呼叫者建立該類物件,通常用於某些特殊的類結構設計。
4.抽象類的子類,必須重寫抽象父類中所有的抽象方法,否則,編譯無法通過而報錯。除非該子類也是抽象類。
理解:假設不重寫所有抽象方法,則類中可能包含抽象方法。那麼建立物件後,呼叫抽象的方法,沒有意義。
2. 介面
2.1 概述
介面,是Java語言中一種引用型別,是方法的集合,如果說類的內部封裝了成員變數、構造方法和成員方法,那麼介面的內部主要就是封裝了方法,包含抽象方法(JDK 7及以前),預設方法和靜態方法(JDK 8),私有方法 (JDK 9)。
介面的定義,它與定義類方式相似,但是使用 interface 關鍵字。它也會被編譯成.class檔案,但一定要明確它並不是類,而是另外一種引用資料型別。
引用資料型別:陣列,類,介面。
介面的使用:它不能建立物件,但是可以被實現( implements ,類似於被繼承)。一個實現介面的類(可以看做是介面的子類),需要實現介面中所有的抽象方法,建立該類物件,就可以呼叫方法了,否則它必須是一個抽象類。
2.2 定義格式
public interface 介面名稱 {
// 抽象方法
// 預設方法
// 靜態方法
// 私有方法
}
//程式碼舉例
public interface InterFaceName {
// 抽象方法
public abstract void method();
// 預設方法,使用 default 修飾,不可省略,供子類呼叫或者子類重寫。
public default void method1() {
System.out.println("預設方法");
}
// 靜態方法
public static void method2() {
System.out.println("靜態方法");
}
//私有方法
private void method3() {
System.out.println("私有方法");
}
}
2.3 介面的使用
介面需要配合類來使用。
類與介面的關係為實現關係,即類實現介面,該類可以稱為介面的實現類,也可以稱為介面的子類。實現的動作類似繼承,格式相仿,只是關鍵字不同,實現使用 implements
關鍵字。
2.3.1 介面中抽象方法的使用
非抽象子類實現介面:
- 必須重寫介面中所有抽象方法。
- 繼承了介面的預設方法,即可以直接呼叫,也可以重寫。
2.3.2 介面中預設方法的使用
子類可以繼承,可以重寫,二選一,但是隻能通過實現類的物件來呼叫。
預設方法在JDK7及以前是沒有的,那為什麼JDK8之後新增了預設方法呢?
以前建立了一個介面,並且已經被大量的類實現。
如果需要再擴充這個介面的功能加新的方法,就會導致所有已經實現的子類需要重寫這個方法。
如果在介面中使用預設方法就不會有這個問題。
所以從 JDK8 開始新加了介面預設方法,便於介面的擴充套件。
2.3.3 介面中靜態方法的使用
靜態與.class 檔案相關,只能使用介面名呼叫,不可以通過實現類的類名或者實現類的物件呼叫。
2.3.4 介面中私有方法的使用
- 私有方法:只有預設方法可以呼叫。
- 私有靜態方法:預設方法和靜態方法可以呼叫。
如果一個介面中有多個預設方法,並且方法中有重複的內容,那麼可以抽取出來,封裝到私有方法中,供預設方法去呼叫。從設計的角度講,私有的方法是對預設方法和靜態方法的輔助。
2.3.5 介面的多實現
在繼承體系中,一個類只能繼承一個父類。而對於介面而言,一個類是可以實現多個介面的,這叫做介面的多實現。並且,一個類能繼承一個父類,同時實現多個介面。
實現格式:
class 類名 [extends 父類名] implements 介面名1,介面名2,介面名3... {
// 重寫介面中抽象方法【必須】
// 重寫介面中預設方法【不重名時可選】
}
2.3.5.1 介面的多實現——抽象方法
介面中,有多個抽象方法時,實現類必須重寫所有抽象方法。如果抽象方法有重名的,只需要重寫一次。
2.3.5.2 介面的多實現——預設方法
介面中,有多個預設方法時,實現類都可繼承使用。如果預設方法有重名的,必須重寫一次。
2.3.5.3 介面的多實現——靜態方法
介面中,存在同名的靜態方法並不會衝突,原因是隻能通過各自介面名訪問靜態方法。
2.3.6 介面和繼承類的優先順序
我們看下程式碼:
interface A {
public default void methodA(){
System.out.println("AAAAAAAAAAAA");
}
}
class D {
public void methodA(){
System.out.println("DDDDDDDDDDDD");
}
}
class C extends D implements A {
// 未重寫methodA方法
}
public static void main(String[] args) {
C c = new C();
c.methodA();
}
輸出結果為:
DDDDDDDDDDDD
由此可知:
當一個類,既繼承一個父類,又實現若干個介面時,父類中的成員方法與介面中的預設方法重名,子類就近選擇執 行父類的成員方法。
3. 抽象類和介面的區別
3.1 相同點
- 都不能被例項化
- 介面的實現類或抽象類的子類都只有實現了介面或抽象類中的方法後才能例項化。
3.2 不同點
-
介面只有定義,不能有方法的實現,java 1.8中可以定義預設方法,而抽象類可以有定義與實現,方法可在抽象類中實現。
-
實現介面的關鍵字為
implements
,繼承抽象類的關鍵字為extends
。一個類可以實現多個介面,但一個類只能繼承一個抽象類。所以,使用介面可以間接地實現多重繼承。 -
介面強調特定功能的實現,而抽象類強調所屬關係。
-
介面成員變數預設為
public static final
,必須賦初值,不能被修改;其所有的成員方法都是public
、abstract
的。抽象類中成員變數預設default
,可在子類中被重新定義,也可被重新賦值;抽象方法被abstract
修飾,不能被private、static
、synchronized
和native
等修飾,必須以分號結尾,不帶花括號。