day10【接口、多態】

一、接口定義

接口就是多個類的公共規範。
接口是一種引用數據類型,最重要的內容就是其中的:抽象方法。

如何定義一個接口的格式:

public interface 接口名稱 {
    // 接口內容
}

備註:換成了關鍵字interface之後,編譯生成的字節碼文件仍然是:.java --> .class。

  • 如果是Java 7,那麼接口中可以包含的內容有:
  1. 常量
  2. 抽象方法
  • 如果是Java 8,還可以額外包含有:
  1. 默認方法
  2. 靜態方法
  • 如果是Java 9,還可以額外包含有:
  1. 私有方法

接口使用步驟:

  1. 接口不能直接使用,必須有一個“實現類”來“實現”該接口。
    格式:
public class 實現類名稱 implements 接口名稱 {
    // ...
}
  1. 接口的實現類必須覆蓋重寫(實現)接口中所有的抽象方法。
    實現:去掉abstract關鍵字,加上方法體大括號。
  2. 創建實現類的對象,進行使用。

注意事項: 如果實現類並沒有覆蓋重寫接口中所有的抽象方法,那麼這個實現類自己就必須是抽象類。

二、接口中可包含的四種方法,一種常量

四種方法,一種常量
  1. 抽象方法
  2. 默認方法
  3. 靜態方法
  4. 私有方法
    常量
四種方法格式:
  • 常量
    格式:
    [public] [static] [final] 數據類型 常量名稱 = 數據值;

注意事項:

  1. 接口當中的常量,可以省略public static final,注意:不寫也照樣是這樣。
  2. 接口當中的常量,必須進行賦值;不能不賦值。
  3. 接口中常量的名稱,使用完全大寫的字母,用下劃線進行分隔。(推薦命名規則)

示例:

public interface MyInterfaceConst {

    // 這其實就是一個常量,一旦賦值,不可以修改
    public static final int NUM_OF_MY_CLASS = 12;

}

1. 抽象方法
格式:
[public] [abstract] 返回值類型 方法名稱(參數列表);

注意:

  1. 接口當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract
  2. 這兩個關鍵字修飾符,可以選擇性地省略。(今天剛學,所以不推薦。)
  3. 方法的三要素,可以隨意定義。

實例:

public interface MyInterfaceAbstract {

    // 這是一個抽象方法
    public abstract void methodAbs1();

    // 這也是抽象方法
    abstract void methodAbs2();

    // 這也是抽象方法
    public void methodAbs3();

    // 這也是抽象方法
    void methodAbs4();

}

2. 默認方法
格式:
[public] default 返回值類型 方法名稱(參數列表) { 方法體 }

備註:接口當中的默認方法,可以解決接口升級的問題。
默認方法存在的意義:有自己的方法體,不需要在“實現類“中重寫也可以調用,就不需要升級那些已經投入生產的實現類,便於後期的升級。

public interface MyInterfaceDefault {

    // 抽象方法
    public abstract void methodAbs();

    // 新添加了一個抽象方法
//    public abstract void methodAbs2();

    // 新添加的方法,改成默認方法
    public default void methodDefault() {
        System.out.println("這是新添加的默認方法");
    }

}

3. 靜態方法
格式:
[public] static 返回值類型 方法名稱(參數列表) { 方法體 }

注意:應該通過接口名稱進行調用,不能通過實現類對象調用接口靜態方法
示例:

public interface MyInterfaceStatic {

    public static void methodStatic() {
        System.out.println("這是接口的靜態方法!");
    }

}

4. 私有方法
普通私有方法:private 返回值類型 方法名稱(參數列表) { 方法體 }
靜態私有方法:private static 返回值類型 方法名稱(參數列表) { 方法體 }

格式:

  1. 普通私有方法,解決多個默認方法之間重複代碼問題
    格式:
    private 返回值類型 方法名稱(參數列表) {
    方法體
    }

  2. 靜態私有方法,解決多個靜態方法之間重複代碼問題
    格式:
    private static 返回值類型 方法名稱(參數列表) {
    方法體
    }

注意:private的方法只有接口自己才能調用,不能被實現類或別人使用。
爲什麼要有靜態私有方法:因爲靜態方法不能調用普通變量和方法,只能設一個靜態私有方法被調用

普通私有方法示例:

public interface MyInterfacePrivateA {

    public default void methodDefault1() {
        System.out.println("默認方法1");
        methodCommon();
    }

    public default void methodDefault2() {
        System.out.println("默認方法2");
        methodCommon();
    }

    private void methodCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }

}

靜態私有方法示例:

public interface MyInterfacePrivateB {

    public static void methodStatic1() {
        System.out.println("靜態方法1");
        methodStaticCommon();
    }

    public static void methodStatic2() {
        System.out.println("靜態方法2");
        methodStaticCommon();
    }

    private static void methodStaticCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }

}
接口注意事項:
  1. 接口是沒有靜態代碼塊或者構造方法的。
  2. 一個類的直接父類是唯一的,但是一個類可以同時實現多個接口。
    格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
    // 覆蓋重寫所有抽象方法
}
  1. 如果實現類所實現的多個接口當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
  2. 如果實現類沒有覆蓋重寫所有接口當中的所有抽象方法,那麼實現類就必須是一個抽象類
  3. 如果實現類所實現的多個接口當中,存在重複的默認方法,那麼實現類一定要對沖突的默認方法進行覆蓋重寫。
  4. 一個類如果父類當中的方法,和接口當中的默認方法產生了衝突,優先用父類當中的方法。

三、多態

1、多態定義

代碼當中體現多態性,其實就是一句話:父類引用指向子類對象。

格式:
父類名稱 對象名 = new 子類名稱();
或者:
接口名稱 對象名 = new 實現類名稱();

示例:

public class Demo01Multi {

    public static void main(String[] args) {
        // 使用多態的寫法
        // 左側父類的引用,指向了右側子類的對象
        Fu obj = new Zi();

        obj.method();
        obj.methodFu();
    }
}
2、多態,訪問成員變量和方法的方式

訪問成員變量的兩種方式:

  1. 直接通過對象名稱訪問成員變量:看等號左邊是誰,優先用誰,沒有則向上找。
  2. 間接通過成員方法訪問成員變量:看該方法屬於誰,優先用誰,沒有則向上找。

訪問成員方法的規則是:
看new的是誰,就優先用誰,沒有則向上找。

對比一下:
成員變量:編譯看左邊,運行還看左邊。
成員方法:編譯看左邊,運行看右邊。

3、轉型
  • 向上轉型:多態本身是子類類型向父類類型向上轉換的過程,這個過程是默認的。
    當父類引用指向一個子類對象時,便是向上轉型。
    使用格式:
父類類型 變量名 = new 子類類型();
如:Animal a = new Cat();
  • 向下轉型:父類類型向子類類型向下轉換的過程,這個過程是強制的。
    使用格式:
子類類型 變量名 = (子類類型) 父類變量名;:Cat c =(Cat) a;

爲什麼要轉型 當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤。也就是說,不能調用子類擁
有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給我們帶來的一點"小麻煩"。所以,想要調用子 類特有的方法,必須做向下轉型。

  • instanceof
    如何才能知道一個父類引用的對象,本來是什麼子類?
    格式:
對象 instanceof 類名稱

這將會得到一個boolean值結果,也就是判斷前面的對象能不能當做後面類型的實例。

示例:

public class Test {
	public static void main(String[] args) {
	// 向上轉型
	Animal a = new Cat();
	a.eat(); // 調用的是 Cat 的 eat
	// 向下轉型
	if (a instanceof Cat){
		Cat c = (Cat)a;
		c.catchMouse(); // 調用的是 Cat 的 catchMouse
		} else if (a instanceof Dog){
		Dog d = (Dog)a;
		d.watchHouse(); // 調用的是 Dog 的 watchHouse
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章