目錄
- 1. 概述
- 2. 定義格式
- 常量
- 抽象方法
- 默認方法和靜態方法
- 私有方法
- 3. 基本的實作
- 實作的概述
- 抽象方法的使用
- 默認方法的使用
- 靜態方法的使用
- 私有方法的使用
- 4. 介面的多實作
- 抽象方法
- 默認方法
- 靜態方法
- 方法重名時的優先級問題
- 5. 介面的多繼承
- 6. 介面的其他特點
- 7. 抽象類和介面的區別
1. 概述
介面,是Java語言中一種參考資料型別,是方法的集合,如果說類的內部封裝了成員變數、構造方法和成員方法,那么介面的內部主要就是封裝了方法,包含抽象方法(JDK 7及以前),默認方法和靜態方法(JDK 8),私有方法(JDK 9),
在Java中,介面表示一種規范/約束,要求實作者必須遵循該規范:用來約束使用者應該怎么做,繼承是一個"是不是"的關系,而介面實作則是 "能不能"的關系,是行為的抽象,
介面的定義,它與定義類方式相似,但是使用 interface 關鍵字,介面也是定義在 .java 檔案中的,它也會被編譯成 .class檔案,但一定要明確它并不是類,而是另外一種參考資料型別,
class 類名.java --> .class 檔案
interface 介面名.java --> .class 檔案
介面的使用,它不能創建物件,但是可以被實作(implements ,類似于被繼承),一個實作介面的類(可以看做是介面的子類),需要實作介面中所有的抽象方法,創建該類物件,就可以呼叫方法了,否則它必須宣告為抽象類,
2. 定義格式
介面只能使用 public abstract 關鍵字修飾,abstract 一般不寫,
public interface 介面名稱 {
// 常量
// 抽象方法 實作類必須全部重寫
// 默認方法 實作類可以重寫,也可以直接使用
// 靜態方法 介面名直接呼叫
// 私有方法 本介面中,自己使用
}
public 關鍵字是常量、抽象方法、默認方法、靜態方法的默認修飾符,可以省略,
常量
介面中,無法定義成員變數,但是可以定義常量,其值不可以改變,默認使用 public static final 修飾,修飾符可省略
定義介面:
public interface LiveAble {
int NUM0; // 錯誤,必須賦值
int NUM1 =10; // 正確,省去了默認修飾符 public static final
public static final int NUM2= 100; // 正確,完整寫法
}
定義測驗類:
public class InterfaceDemo {
public static void main(String[] args) {
System.out.println(Live.NUM1);
System.out.println(Live.NUM2);
}
}
輸出結果:
10
100
抽象方法
抽象方法:默認使用 public abstract 修飾,可以省略,該方法供子類實作使用,
代碼如下:
public interface InterfaceName {
public abstract void method();
}
默認方法和靜態方法
默認方法:使用 public default 修飾,default 不可省略,有方法體,供子類呼叫或者子類重寫,
靜態方法:使用 public static 修飾,static 不可省略,有方法體,供介面直接呼叫,
代碼如下:
public interface InterfaceName {
public default void method() {
// 執行陳述句
}
public static void method2() {
// 執行陳述句
}
}
私有方法
私有方法:使用 private 修飾,不可省略,供介面中的默認方法或者靜態方法呼叫,
代碼如下:
public interface InterfaceName {
private void method() {
// 執行陳述句
}
}
3. 基本的實作
實作的概述
類與介面的關系為實作關系,即類實作介面,該類可以稱為介面的實作類,也可以稱為介面的子類,實作的動作類似繼承,格式相仿,只是關鍵字不同,實作使用 implements 關鍵字,
非抽象子類實作介面:
- 必須重寫介面中所有抽象方法,
- 繼承了介面的默認方法,既可以直接呼叫,也可以重寫,
實作格式:
class 類名 implements 介面名 {
// 重寫介面中抽象方法【必須】
// 重寫介面中默認方法【可選】
}
抽象方法的使用
必須全部實作,代碼如下:
定義介面:
public interface LiveAble {
// 定義抽象方法
public abstract void eat();
public abstract void sleep();
}
定義實作類:
public class Animal implements LiveAble {
@Override
public void eat() {
System.out.println("吃東西");
}
@Override
public void sleep() {
System.out.println("晚上睡覺");
}
}
定義測驗類:
public class InterfaceDemo {
public static void main(String[] args) {
// 創建子類物件
Animal a = new Animal();
// 呼叫實作后的方法
a.eat();
a.sleep();
}
}
輸出結果:
吃東西
晚上睡
默認方法的使用
可以繼承,可以重寫,二選一,但是只能通過實作類的物件來呼叫,
- 繼承默認方法,代碼如下:
定義介面:
public interface LiveAble {
public default void fly(){
System.out.println("天上飛");
}
}
定義實作類:
public class Animal implements LiveAble {
// 繼承,什么都不用寫,直接呼叫
}
定義測驗類:
public class InterfaceDemo {
public static void main(String[] args) {
// 創建子類物件
Animal a = new Animal();
// 呼叫默認方法
a.fly();
}
}
輸出結果:
天上飛
- 重寫默認方法,代碼如下:
定義介面:
public interface LiveAble {
public default void fly(){
System.out.println("天上飛");
}
}
定義實作類:
public class Animal implements LiveAble {
@Override
public void fly() {
System.out.println("自由自在的飛");
}
}
定義測驗類:
public class InterfaceDemo {
public static void main(String[] args) {
// 創建子類物件
Animal a = new Animal();
// 呼叫重寫方法
a.fly();
}
}
輸出結果:
自由自在的飛
靜態方法的使用
介面中的靜態方法只能使用介面名呼叫,實作類不能重寫,不可以通過實作類的類名或者實作類的物件呼叫,代碼如下:
定義介面:
public interface LiveAble {
public static void run(){
System.out.println("跑起來~~~");
}
}
定義實作類:
public class Animal implements LiveAble {
// 無法重寫靜態方法
}
定義測驗類:
public class InterfaceDemo {
public static void main(String[] args) {
// Animal.run(); // 【錯誤】無法繼承方法,也無法呼叫
LiveAble.run(); //
}
}
輸出結果:
跑起來~~~
私有方法的使用
- 私有非靜態方法:只有默認方法可以呼叫;解決多個默認方法之間重復代碼問題
- 私有靜態方法:默認方法和靜態方法可以呼叫,解決多個靜態方法之間重復代碼問題
因為是私有的,所以子介面和實作類不能覆寫重寫,
如果一個介面中有多個默認方法,并且方法中有重復的內容,那么可以抽取出來,封裝到私有方法中,供默認方法去呼叫,從設計的角度講,私有的方法是對默認方法和靜態方法的輔助,
定義介面:
public interface LiveAble {
default void func(){
func1();
LiveAble.func2();
}
private void func1(){
System.out.println("func1~~~");
}
private static void func2(){
System.out.println("func2~~~");
}
}
4. 介面的多實作
之前學過,在繼承體系中,一個類只能繼承一個父類,而對于介面而言,一個類是可以實作多個介面的,這叫做介面的多實作,并且,一個類能繼承一個父類,同時實作多個介面,
實作格式:
修飾符 class 類名 [extends 父類名] implements 介面名1, 介面名2, 介面名3... {
// 重寫介面中抽象方法【必須】
// 重寫介面中默認方法【不重名時可選】
}
抽象方法
介面中,有多個抽象方法時,實作類必須重寫所有的抽象方法,如果多個介面的抽象方法有重名的,只需要重寫一次,代碼如下:
定義多個介面:
interface A {
public abstract void showA();
public abstract void show();
}
interface B {
public abstract void showB();
public abstract void show();
}
定義實作類:
public class C implements A, B{
@Override
public void showA() {
System.out.println("showA");
}
@Override
public void showB() {
System.out.println("showB");
}
@Override
public void show() {
System.out.println("show");
}
}
默認方法
介面中,有多個默認方法時,實作類都可繼承使用,如果多個介面的默認方法有重名的,必須重寫一次,代碼如下:
定義多個介面:
interface A {
public default void methodA(){}
public default void method(){}
}
interface B {
public default void methodB(){}
public default void method(){}
}
定義實作類:
public class C implements A,B{
@Override
public void method() {
System.out.println("method");
}
}
靜態方法
多個介面中,存在同名的靜態方法并不會沖突,原因是只能通過各自介面名訪問靜態方法,
public interface MyInterface {
public static void inter(){
system.out.println("介面靜態方法");
}
}
public class Test {
public static void main(String[] args){
//介面名直接呼叫
MyInterface.inter();
}
}
方法重名時的優先級問題
當一個類,既繼承一個父類,又實作若干個介面時,若父類中的成員方法與介面中的默認方法重名且子類中未重寫,子類就近選擇執行父類的成員方法,代碼如下:
定義介面:
interface A {
public default void methodA() {
System.out.println("AAAAAAAAAAAA");
}
}
定義父類:
class B {
public void methodA() {
System.out.println("BBBBBBBBBBBB");
}
}
定義子類:
class C extends B implements A {
// 未重寫methodA方法
}
定義測驗類:
public class Test {
public static void main(String[] args) {
C c = new C();
c.methodA();
}
}
輸出結果:
BBBBBBBBBBBB
5. 介面的多繼承
一個介面能繼承另一個或者多個介面,這和類之間的繼承比較相似,介面的繼承使用 extends 關鍵字,子介面繼承父介面的方法,如果父介面中的默認方法有重名的,那么子介面需要重寫一次,代碼如下:
定義父介面:
interface A {
public default void method(){
System.out.println("AAAAAAAAAAAAAAAAAAA");
}
}
interface B {
public default void method(){
System.out.println("BBBBBBBBBBBBBBBBBBB");
}
}
定義子介面:
interface C extends A,B {
@Override
public default void method() {
System.out.println("CCCCCCCCCCCCCCCCCCC");
}
}
子介面重寫默認方法時,default關鍵字必須保留,
子類重寫默認方法時,default關鍵字不可以保留,
介面解決了其他語言中多繼承的弊端,將多繼承這種機制在java中通過多實作來完成:
-
多繼承的弊端:當多個父類中有相同功能時,子類呼叫會產生不確定性,核心原因就是在于多繼承父類中方法有主體,而導致呼叫運行時,不確定運行哪個主體內容,
-
為什么多實作能解決這種沖突?:因為介面中的功能都沒有方法體,需要由子類來明確,
6. 介面的其他特點
介面沒有構造器、代碼塊,因為介面中沒有類變數和實體變數需要初始化,只有常量
介面不能直接實體化創建物件,因為沒有構造器
7. 抽象類和介面的區別
通過實體進行分析和代碼演示抽象類和介面的用法,
1、舉例:
? 犬:
? 行為:
? 吼叫;
? 吃飯;
? 緝毒犬:
? 行為:
? 吼叫;
? 吃飯;
? 緝毒;
2、思考:
? 由于犬分為很多種類,他們吼叫和吃飯的方式不一定相同,在描述的時候不能具體化,也就是吼叫和吃飯的行為不能明確,當描述行為時,行為的具體動作不能明確,這時,可以將這個行為寫成抽象行為,那么這個類也就是抽象類,
? 可是當緝毒犬有其他額外功能時,而這個功能并不在這個事物的體系中,這時可以讓緝毒犬具備犬科自身特點的同時也有其他額外功能,可以將這個額外功能到定義介面中,實作緝毒功能的既可以緝毒警察,也可以是緝毒犬,
interface 緝毒 {
public abstract void 緝毒();
}
//定義犬科的共性功能
abstract class 犬科{
public abstract void 吃飯();
public abstract void 吼叫();
}
// 緝毒犬屬于犬科一種,讓其繼承犬科,獲取到犬科的特性,
//由于緝毒犬具有緝毒功能,那么它只要實作緝毒介面即可,這樣即保證緝毒犬具備犬科的特性,也擁有了緝毒的功能
class 緝毒犬 extends 犬科 implements 緝毒 {
public void 緝毒() {
}
void 吃飯() {
}
void 吼叫() {
}
}
3、通過上面的例子總結介面和抽象類的區別:
相同點:
都位于繼承的頂端,用于被其他類實作或繼承;
都不能直接實體化物件;
都包含抽象方法,其子類都必須實作這些抽象方法;
區別:
抽象類中可以變數、常量,抽象方法,非抽象方法,構造方法;介面中可以有常量,抽象方法( JDK8新增:默認方法,靜態方法;JDK9新增:私有方法)
一個類只能繼承一個直接父類(可能是抽象類),卻可以實作多個介面(介面彌補了Java的單繼承的局限性)
抽象類為繼承體系中的共性內容,介面為繼承體系中的擴展功能
-
成員區別
- 抽象類
- 變數,常量;抽象方法,非抽象方法,構造方法
- 介面
- 常量;抽象方法( JDK8:默認方法,靜態方法;JDK9:私有方法)
- 抽象類
-
關系區別
- 類與類
- 繼承,單繼承
- 類與介面
- 實作,可以單實作,也可以多實作
- 介面與介面
- 繼承,單繼承,多繼承
- 類與類
-
設計理念區別
-
抽象類
- 對類抽象,包括屬性、行為
-
介面
- 對行為抽象,主要是行為
-
如果抽象類和介面都可以使用的話,優先使用介面,因為避免了單繼承的局限性
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/51211.html
標籤:Java
