一、接口定義
接口就是多個類的公共規範。
接口是一種引用數據類型,最重要的內容就是其中的:抽象方法。
如何定義一個接口的格式:
public interface 接口名稱 {
// 接口內容
}
備註:換成了關鍵字interface之後,編譯生成的字節碼文件仍然是:.java --> .class。
- 如果是Java 7,那麼接口中可以包含的內容有:
- 常量
- 抽象方法
- 如果是Java 8,還可以額外包含有:
- 默認方法
- 靜態方法
- 如果是Java 9,還可以額外包含有:
- 私有方法
接口使用步驟:
- 接口不能直接使用,必須有一個“實現類”來“實現”該接口。
格式:
public class 實現類名稱 implements 接口名稱 {
// ...
}
- 接口的實現類必須覆蓋重寫(實現)接口中所有的抽象方法。
實現:去掉abstract關鍵字,加上方法體大括號。 - 創建實現類的對象,進行使用。
注意事項: 如果實現類並沒有覆蓋重寫接口中所有的抽象方法,那麼這個實現類自己就必須是抽象類。
二、接口中可包含的四種方法,一種常量
四種方法,一種常量
- 抽象方法
- 默認方法
- 靜態方法
- 私有方法
常量
四種方法格式:
- 常量
格式:
[public] [static] [final] 數據類型 常量名稱 = 數據值;
注意事項:
- 接口當中的常量,可以省略public static final,注意:不寫也照樣是這樣。
- 接口當中的常量,必須進行賦值;不能不賦值。
- 接口中常量的名稱,使用完全大寫的字母,用下劃線進行分隔。(推薦命名規則)
示例:
public interface MyInterfaceConst {
// 這其實就是一個常量,一旦賦值,不可以修改
public static final int NUM_OF_MY_CLASS = 12;
}
1. 抽象方法
格式:
[public] [abstract] 返回值類型 方法名稱(參數列表);
注意:
- 接口當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract
- 這兩個關鍵字修飾符,可以選擇性地省略。(今天剛學,所以不推薦。)
- 方法的三要素,可以隨意定義。
實例:
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 返回值類型 方法名稱(參數列表) { 方法體 }
格式:
-
普通私有方法,解決多個默認方法之間重複代碼問題
格式:
private 返回值類型 方法名稱(參數列表) {
方法體
} -
靜態私有方法,解決多個靜態方法之間重複代碼問題
格式:
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");
}
}
接口注意事項:
- 接口是沒有靜態代碼塊或者構造方法的。
- 一個類的直接父類是唯一的,但是一個類可以同時實現多個接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆蓋重寫所有抽象方法
}
- 如果實現類所實現的多個接口當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
- 如果實現類沒有覆蓋重寫所有接口當中的所有抽象方法,那麼實現類就必須是一個抽象類。
- 如果實現類所實現的多個接口當中,存在重複的默認方法,那麼實現類一定要對沖突的默認方法進行覆蓋重寫。
- 一個類如果父類當中的方法,和接口當中的默認方法產生了衝突,優先用父類當中的方法。
三、多態
1、多態定義
代碼當中體現多態性,其實就是一句話:父類引用指向子類對象。
格式:
父類名稱 對象名 = new 子類名稱();
或者:
接口名稱 對象名 = new 實現類名稱();
示例:
public class Demo01Multi {
public static void main(String[] args) {
// 使用多態的寫法
// 左側父類的引用,指向了右側子類的對象
Fu obj = new Zi();
obj.method();
obj.methodFu();
}
}
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
}
}
}