接口概述
接口,是Java語言中一種引用類型,是方法的集合,如果說類的內部封裝了成員變量、構造方法和成員方法,那麼 接口的內部主要就是封裝了方法,包含抽象方法(JDK 7及以前),默認方法和靜態方法(JDK 8),私有方法 (JDK 9)。 接口的定義,它與定義類方式相似,但是使用 interface 關鍵字。它也會被編譯成.class文件,但一定要明確它並 不是類,而是另外一種引用數據類型。 引用數據類型:數組,類,接口。 接口的使用,它不能創建對象,但是可以被實現( implements ,類似於被繼承)。一個實現接口的類(可以看做 是接口的子類),需要實現接口中所有的抽象方法,創建該類對象,就可以調用方法了,否則它必須是一個抽象 類。 接口就是多個類的公共的規範標準。
接口的定義
定義接口的格式:
public interface 接口名稱 {
// 抽象方法
// 默認方法
// 靜態方法
// 私有方法
}
備註:換成了關鍵字interface之後,編譯生成的字節碼文件仍然是:.java --> .class。
如果是(JDK 7及以前),那麼接口中可以包含的內容有:
- 常量
- 抽象方法
定義抽象方法
格式:
- public abstract 返回值類型 方法名稱(參數列表);
例如:
package demo01;
public interface DemoInterface01 {
//定義抽象方法
public abstract void method1();
//定義抽象方法
abstract void method2();
//定義抽象方法
void method3();
//定義抽象方法
public void method4();
}
注意事項:
- 接口當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract
- 這兩個關鍵字修飾符,可以選擇性地省略。
- 方法的三要素,可以根據業務需要隨意定義
定義常量
接口當中也可以定義“成員變量”,但是必須使用public static final三個關鍵字進行修飾。從效果上看,這其實就是接口的【常量】。
格式:
- public static final 數據類型 常量名稱 = 數據值;
例如:
public interface MyInterfaceConst {
// 這其實就是一個常量,一旦賦值,不可以修改
public static final int NUM_OF_MY_CLASS = 12;
}
注意事項:
- 接口當中的常量,可以省略public static final,注意:不寫也照樣是這樣。
- 接口當中的常量,必須進行賦值;不能不賦值。
- 接口中常量的名稱,使用完全大寫的字母,用下劃線進行分隔。(推薦命名規則)任何
接口的實現
類與接口的關係爲實現關係,即類實現接口,該類可以稱爲接口的實現類,也可以稱爲接口的子類。實現的動作類 似繼承,格式相仿,只是關鍵字不同,實現使用 implements 關鍵字。 非抽象子類實現接口: 必須重寫接口中所有抽象方法,如果繼承了接口的默認方法,即可以直接調用,也可以重寫。
接口使用步驟:
1: 接口不能直接使用,必須有一個“實現類”來“實現”該接口。
格式:
public class 實現類名稱 implements 接口名稱 {
// ...
}
2:接口的實現類必須覆蓋重寫(實現)接口中所有的抽象方法。
3: 創建實現類的對象,進行使用。
注意事項:
- 如果實現類並沒有覆蓋重寫接口中所有的抽象方法,那麼這個實現類自己就必須是抽象類。
代碼舉例:
定義接口MyInterface01
package myDemo01;
public interface MyInterface01 {
//定義接口常量
public static final int value = 18;
//定義接口抽象方法
public abstract void print();
}
定義接口實現類MyInterface01Imp
package myDemo01;
//1. 接口不能直接使用,必須有一個“實現類”來“實現”該接口。
public class MyInterface01Imp implements MyInterface01 {
//2:接口的實現類必須覆蓋重寫(實現)接口中所有的抽象方法。
@Override
public void print() {
System.out.println("我接口中的常量值是"+value);
}
}
定義測試類Interface01Test
package myDemo01;
public class Interface01Test {
public static void main(String[] args) {
//3: 創建實現類的對象,進行使用。
MyInterface01Imp imp = new MyInterface01Imp();
//使用實現類中的默認方法
imp.print();
//訪問接口中的常量
System.out.println(MyInterface01.value);
}
}
代碼執行後的結果
從Java 8開始,接口裏還可以定義默認方法。
格式:
public default 返回值類型 方法名稱(參數列表) {
方法體
}
備註:接口當中的默認方法,可以解決接口升級的問題。
默認方法如何使用:
- 默認方法可以繼承,可以重寫,二選一,但是隻能通過實現類的對象來調用。
代碼舉例
定義接口MyInterface02
package myDemo01;
public interface MyInterface02 {
//定義默認方法
public default void defaultMethod() {
System.out.println("我是老接口");
}
}
定義實現類MyInterface02ImpA繼承接口中的默認方法
package myDemo01;
//定義實現類,實現接口
public class MyInterface02ImpA implements MyInterface02 {
//默認方法可以繼承
}
定義實現類MyInterface02ImpB重寫接口中的默認方法
package myDemo01;
public class MyInterface02ImpB implements MyInterface02 {
// 重寫默認方法
@Override
public void defaultMethod() {
System.out.println("接口升級了");
}
}
定義測試類Interface02Test
package myDemo01;
public class Interface02Test {
public static void main(String[] args) {
//創建實現類對象
MyInterface02ImpA impA = new MyInterface02ImpA();
// 調用默認方法,實際運行的是接口中繼承下來的方法
impA.defaultMethod();
// 創建了實現類對象
MyInterface02ImpB impB = new MyInterface02ImpB();
// 調用,默認方法,實際運行的是右側實現類(重寫之後的方法)。
impB.defaultMethod();
}
}
代碼執行後的結果
從Java 8開始,接口當中還允許定義靜態方法。
格式:
public static 返回值類型 方法名稱(參數列表) {
方法體
}
注意:靜態方法也是有方法體
靜態方法的使用:
- 靜態與.class 文件相關,只能使用接口名調用,不可以通過實現類的類名或者實現類的對象調用
- 格式:接口名稱.靜態方法名(參數);
- 靜態方法無法重寫
代碼舉例
定義接口MyInterface03
package myDemo01;
public interface MyInterface03 {
public static void method() {
System.out.println("我是接口中的靜態方法");
}
}
定義接口實現類MyInterface03Imp
package myDemo01;
public class MyInterface03Imp implements MyInterface03 {
// 無法重寫靜態方法
}
定義測試類Interface03Test
package myDemo01;
public class Interface03Test {
public static void main(String[] args) {
// 創建了實現類對象
MyInterface03Imp imp = new MyInterface03Imp();
// 錯誤寫法!實現類調用靜態方法 imp.method;
// 直接通過接口名稱調用靜態方法
MyInterface03.method();
}
}
代碼執行後結果
從Java 9開始,接口當中還允許定義私有方法
如果一個接口中有多個默認方法,並且方法中有重複的內容,那麼可以抽取出來,封裝到私有方法中,供默認方法 去調用。從設計的角度講,私有的方法是對默認方法和靜態方法的輔助。
1. 普通私有方法,解決多個默認方法之間重複代碼問題
格式:
private 返回值類型 方法名稱(參數列表) {
方法體
}
2. 靜態私有方法,解決多個靜態方法之間重複代碼問題
格式:
private static 返回值類型 方法名稱(參數列表) {
方法體
}
私有方法的使用
- 私有方法:只有在接口當中的默認方法裏調用。
- 私有靜態方法:只有在接口當中的默認方法和靜態方法裏調用。
代碼舉例
定義接口MyInterface04
package myDemo01;
public interface MyInterface04 {
//定義默認方法
public default void methodDefault1() {
//私有方法只有接口中的默認方法可以調用。
methodPrivate();
//私有靜態方法:接口中的默認方法可以調用
methodStaticPrivate();
}
public default void methodDefault2() {
methodPrivate();
methodStaticPrivate();
}
//定義私有方法
private void methodPrivate() {
System.out.println("我是私有方法,我抽取了默認方法中的重複代碼");
}
//定義靜態方法
public static void methodStatic1() {
//私有靜態方法:接口中的靜態方法也可以調用
methodStaticPrivate();
}
public static void methodStatic2() {
methodStaticPrivate();
}
//定義私有靜態方法
private static void methodStaticPrivate() {
System.out.println("我是私有靜態方法,我抽取了靜態方法中的重複代碼");
}
}
定義接口實現類MyInterface04Imp
package myDemo01;
public class MyInterface04Imp implements MyInterface04 {
}
定義接口的測試類Interface04Tes
package myDemo01;
public class Interface04Test {
public static void main(String[] args) {
//創建接口實現類對象
MyInterface04Imp imp = new MyInterface04Imp();
//調用默認方法
imp.methodDefault1();
System.out.println("===========");
imp.methodDefault2();
System.out.println("===========");
//調用接口中靜態方法
MyInterface04.methodStatic1();
System.out.println("===========");
MyInterface04.methodStatic2();
}
}
代碼執行後的結果
使用接口的時候,需要注意:
1:接口是沒有靜態代碼塊或者構造方法的。因爲沒有構造方法,不能創建對象。
2:一個類的直接父類是唯一的,但是一個類可以同時實現多個接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆蓋重寫所有抽象方法
}
3: 如果實現類所實現的多個接口當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
4:如果實現類沒有覆蓋重寫所有接口當中的所有抽象方法,那麼實現類就必須是一個抽象類。
5:如果實現類鎖實現的多個接口當中,存在重複的默認方法,那麼實現類一定要對衝突的默認方法進行覆蓋重寫。
6:一個類如果直接父類當中的方法,和接口當中的默認方法產生了衝突,優先用父類當中的方法。