第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Java 接口

本小節(jié)我們將學(xué)習(xí) Java 接口(interface),通過本小節(jié)的學(xué)習(xí),你將了解到什么是接口、為什么需要接口、如何定義和實(shí)現(xiàn)接口,以及接口的特點(diǎn)等內(nèi)容。最后我們也將對(duì)比抽象類和接口的區(qū)別。

1. 概念

Java 接口是一系列方法的聲明,是一些方法特征的集合,一個(gè)接口只有方法的特征沒有方法的實(shí)現(xiàn)。

在 Java 中,被關(guān)鍵字 interface 修飾的 class 就是一個(gè)接口。接口定義了一個(gè)行為協(xié)議,可以由類層次結(jié)構(gòu)中任何位置的任何類實(shí)現(xiàn)。接口中定義了一組抽象方法,都沒有具體實(shí)現(xiàn),實(shí)現(xiàn)該接口的類必須實(shí)現(xiàn)該接口中定義的所有抽象方法。

2. 為什么需要接口

我們知道 Java 僅支持單繼承,也就是說一個(gè)類只允許有一個(gè)直接父類,這樣保證了數(shù)據(jù)的安全。Java 不支持下圖所示的多繼承:

接口就是為了解決 Java 單繼承這個(gè)弊端而產(chǎn)生的,雖然一個(gè)類只能有一個(gè)直接父類,但是它可以實(shí)現(xiàn)多個(gè)接口,沒有繼承關(guān)系的類也可以實(shí)現(xiàn)相同的接口。繼承和接口的雙重設(shè)計(jì)既保持了類的數(shù)據(jù)安全也變相實(shí)現(xiàn)了多繼承。

3. 接口的定義和實(shí)現(xiàn)

3.1 定義接口

3.1.1 接口聲明

使用 interface 關(guān)鍵字聲明一個(gè)接口:

public interface Person {
    ...
}

接口聲明需要兩個(gè)元素:interface 關(guān)鍵字和接口名稱,public 修飾符表示該接口可以在任何包的任何類中使用,如果為顯示指定訪問修飾符,則該接口只能被在同包中的類使用。

3.1.2 接口主體

接口主體中,可以定義常量和方法聲明:

public interface Person {
  	final String NAME = "我是Person接口中的常量";
	void walk();
  	void run();
}

上面的 Person 就是一個(gè)接口,這個(gè)接口定義了一個(gè)常量 NAME 和兩個(gè)抽象方法 walk()run()。

接口比抽象類更加 “抽象”,它下面不能擁有具體實(shí)現(xiàn)的方法,必須全部都是抽象方法,所有的方法默認(rèn)都是 public abstract 的,所以在接口主體中的方法,這兩個(gè)修飾符無需顯示指定。

接口除了方法聲明外,還可以包含常量聲明。在接口中定義的所有的常量默認(rèn)都是 publicstatic,和 final 的。

接口中的成員聲明不允許使用 privateprotected 修飾符。

3.2 實(shí)現(xiàn)接口

接口定義了一些行為協(xié)議,而實(shí)現(xiàn)接口的類要遵循這些協(xié)議。implements 關(guān)鍵字用于實(shí)現(xiàn)接口,一個(gè)類可以實(shí)現(xiàn)一個(gè)或多個(gè)接口,當(dāng)要實(shí)現(xiàn)多個(gè)接口時(shí),implements 關(guān)鍵字后面是該類要實(shí)現(xiàn)的以逗號(hào)分割的接口名列表。其語法為:

public class MyClass implements MyInterface1, MyInterface2 {
   ...
}

下面是實(shí)現(xiàn)了 Person 接口的 Student 類的示例代碼:

public class Student implements Person {
    @Override
    public void walk() {
      	// 打印接口中的常量
        System.out.println(Person.NAME);
        System.out.println("學(xué)生可以走路");
    }

    @Override
    public void run() {
        System.out.println("學(xué)生可以跑步");
    }
}

上述代碼中,Student 類實(shí)現(xiàn)了 Person 接口。值得注意的是,可以使用接口名。常量名的方式調(diào)用接口中所聲明的常量:

String name = Person.NAME;

4. 接口繼承

接口也是存在繼承關(guān)系的。接口繼承使用 extends 關(guān)鍵字。例如,聲明兩個(gè)接口 MyInterface1MyInterface2,MyInterface2 繼承自 MyInterface1

// MyInterface1.java
public interface MyInterface1 {
    void abstractMethod1();
}

// MyInterface2.java
public interface MyInterface2 extends MyInterface1 {
    void abstractMethod2();
}

當(dāng)一個(gè)類實(shí)現(xiàn) MyInterface2 接口,將會(huì)實(shí)現(xiàn)該接口所繼承的所有抽象方法:

// MyClass.java
public class MyClass implements MyInterface2 {
    @Override
    public void abstractMethod2() {
				...
    }

    @Override
    public void abstractMethod1() {
				...
    }
}

值得注意的是,一個(gè)接口可以繼承多個(gè)父接口,接口名放在 extends 后面,以逗號(hào)分割,例如:

// MyInterface1.java
public interface MyInterface1 {
    void abstractMethod1();
}

// MyInterface2.java
public interface MyInterface2 {
    void abstractMethod2();
}

// MyInterface3.java
public interface MyInterface3 extends MyInterface1, MyInterface2 {
    void abstractMethod3();
}

補(bǔ)充一點(diǎn),當(dāng)一個(gè)實(shí)現(xiàn)類存在 extends 關(guān)鍵字,那么 implements 關(guān)鍵字應(yīng)該放在其后:

public class MyClass extends SuperClass implements MyInterface {
   ...
}

5. 默認(rèn)方法和靜態(tài)方法

JDK 1.8 開始,接口中可以定義默認(rèn)方法和靜態(tài)方法。與抽象方法不同,實(shí)現(xiàn)類可以不實(shí)現(xiàn)默認(rèn)方法和類方法。

5.1 默認(rèn)方法

5.1.1 聲明

我們可以使用 default 關(guān)鍵字,在接口主題中實(shí)現(xiàn)帶方法體的方法,例如:

public interface Person {
  	void run();
  
  	default void eat() {
      	System.out.println("我是默認(rèn)的吃方法");
    }
}

5.1.2 調(diào)用和重寫

在實(shí)現(xiàn)類中,可以不實(shí)現(xiàn)默認(rèn)方法:

public class Student implements Person {
  	@Override
    public void run() {
        System.out.println("學(xué)生可以跑步");
    }
}

我們也可以在實(shí)現(xiàn)類中重寫默認(rèn)方法,重寫不需要 default 關(guān)鍵字:

public class Student implements Person {
  	@Override
    public void run() {
        System.out.println("學(xué)生可以跑步");
    }
  
  	// 重寫默認(rèn)方法
  	@Override
  	public void eat() {
      	// 使用 接口名.super.方法名() 的方式調(diào)用接口中默認(rèn)方法
      	Person.super.eat();
      	System.out.println("學(xué)生吃東西");
    }
}

如果想要在實(shí)現(xiàn)類中調(diào)用接口的默認(rèn)方法,可以使用接口名.super. 方法名 () 的方式調(diào)用。這里的 接口名.super 就是接口的引用。

5.1.3 使用場(chǎng)景

當(dāng)一個(gè)方法不需要所有實(shí)現(xiàn)類都進(jìn)行實(shí)現(xiàn),可以在接口中聲明該方法為默認(rèn)方法;使用默認(rèn)方法還有一個(gè)好處,當(dāng)接口新增方法時(shí),將方法設(shè)定為默認(rèn)方法,只在需要實(shí)現(xiàn)該方法的類中重寫它,而不需要在所有實(shí)現(xiàn)類中實(shí)現(xiàn)。

5.2 靜態(tài)方法

5.2.1 聲明

使用 static 關(guān)鍵字在接口中聲明靜態(tài)方法,例如:

public interface Person {
    void walk();
    // 聲明靜態(tài)方法
    static void sayHello() {
        System.out.println("Hello imooc!");
    }
}

5.2.2 調(diào)用

類中的靜態(tài)方法只能被子類繼承而不能被重寫,同樣在實(shí)現(xiàn)類中,靜態(tài)方法不能被重寫。如果想要調(diào)用接口中的靜態(tài)方法,只需使用 接口名。類方法名 的方式即可調(diào)用:

public class Student implements Person {
    @Override
    public void walk() {
      	// 調(diào)用接口中的類方法
        Person.sayHello();
        System.out.println("學(xué)生會(huì)走路");
    }
}

6. 接口和抽象類的區(qū)別

  1. 接口的方法默認(rèn)是 public ,所有方法在接口中不能有實(shí)現(xiàn)(Java 8 開始接口方法可以有默認(rèn)實(shí)現(xiàn)),而抽象類可以有非抽象的方法;
  2. 接口中除了 static 、final 變量,不能有其他變量,而抽象類可以;
  3. 一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,但只能實(shí)現(xiàn)一個(gè)抽象類。接口自己本身可以通過 extends 關(guān)鍵字?jǐn)U展多個(gè)接口;
  4. 接口方法默認(rèn)修飾符是 public ,抽象方法可以有 public 、protected 和 default 這些修飾符(抽象方法就是為了被重寫所以不能使用 private 關(guān)鍵字修飾!);
  5. 從設(shè)計(jì)層面來說,抽象是對(duì)類的抽象,是一種模板設(shè)計(jì),而接口是對(duì)行為的抽象,是一種行為的規(guī)范。

7. 多個(gè)接口中的重名成員解決方法

7.1 多個(gè)接口存在重名默認(rèn)方法

例如有兩個(gè)接口 MyInteface1.javaMyInterface2.java,存在相同簽名的默認(rèn)方法:

public interface MyInterface1 {
    default void defaultMethod() {
        System.out.println("我是MyInterface1接口中的默認(rèn)方法");
    }
}

public interface MyInterface2 {
    default void defaultMethod() {
        System.out.println("我是MyInterface2接口中的默認(rèn)方法");
    }
}

當(dāng)實(shí)現(xiàn)類實(shí)現(xiàn)兩個(gè)接口時(shí),同名的默認(rèn)方法將會(huì)發(fā)生沖突,解決辦法是在實(shí)現(xiàn)類中重寫這個(gè)默認(rèn)方法

public class MyClass implements MyInterface1, MyInterface2 {
	public void defaultMethod() {
      	System.out.println("我是重寫的默認(rèn)方法");
    }
}

還有一種情況:實(shí)現(xiàn)類所繼承的父類中也存在與默認(rèn)方法的同名方法,此時(shí)存在三個(gè)同名方法:

// 聲明父類,并在父類中也定義同名方法
public class SuperClass {
  	public void defaultMethod() {
        System.out.println("我是SuperClass中的defaultMethod()方法");
    }
}

// 實(shí)現(xiàn)類繼承父類,并實(shí)現(xiàn)兩個(gè)接口
public class MyClass extends SuperClass implements MyInterface1, MyInterface2 {
}

實(shí)例化 MyClass 類,調(diào)用其 defaultMethod() 方法:

MyClass myClass = new MyClass();
myClass.defaultMethod();

此時(shí)編譯執(zhí)行,不會(huì)報(bào)錯(cuò):

我是SuperClass中的defaultMethod()方法

實(shí)際上,在沒有重寫的情況下,它執(zhí)行了實(shí)現(xiàn)類的父類 SuperClassdefaultMethod() 方法。

7.2 多個(gè)接口中存在重名常量

例如有兩個(gè)接口,存在重名的常量:

public interface MyInterface1 {
    final int NUM = 100;
}

public interface MyInterface2 {
	final int NUM = 200;
}

此時(shí)在實(shí)現(xiàn)類中,我們可以使用接口名。常量名的方式分別調(diào)用:

public MyClass implements MyInterface1, MyInterface2 {
	  System.out.println(MyInterface1.NUM);  	
	  System.out.println(MyInterface2.NUM);  	
}

當(dāng)實(shí)現(xiàn)類將入一個(gè)繼承關(guān)系時(shí):

class SuperClass {
  	static int NUM = 300;
}

public MyClass extends SuperClass implements MyInterface1, MyInterface2 {	
    System.out.println(NUM);
}

當(dāng)父類中的屬性或常量與接口中的常量同名時(shí),子類無法分辨同名的 NUM 是哪一個(gè)。編譯程序?qū)?huì)報(bào)錯(cuò):

MyClass.java:4: 錯(cuò)誤: 對(duì)NUM的引用不明確
        System.out.println(NUM);
                           ^
  SuperClass 中的變量 NUM 和 MyInterface1 中的變量 NUM 都匹配
1 個(gè)錯(cuò)誤

此時(shí)只有在子類中聲明 NUM,才可以通過編譯:

public MyClass extends SuperClass implements MyInterface1, MyInterface2 {
  	int NUM = 3;
	System.out.println(NUM);
}

8. 小結(jié)

通過本小節(jié)的學(xué)習(xí),我們知道了 Java 的接口是為了解決其單繼承的弊端而產(chǎn)生的,可以使用 interface 關(guān)鍵字來聲明一個(gè)接口,接口內(nèi)部不能有具體的方法實(shí)現(xiàn)??梢允褂?implements 關(guān)鍵字來實(shí)現(xiàn)接口,一個(gè)接口可以繼承多個(gè)父接口,接口名放在 extends 后面,以逗號(hào)分割。從 Java 8 開始,接口中可以定義默認(rèn)方法和靜態(tài)方法。