Java之路:介面
介面
介面(interface)是Java所提供的另一種重要技術,是一種特殊的類,它的結構和抽象類非常相似,也具有資料成員與抽象方法,但它與抽象類又有不同,並且Java 8中又添加了新特性。
,而方法會被隱式地指定為public abstract方法且只能是public abstract方法(用其他關鍵字,比如private、protected、static、 final等修飾會報編譯錯誤)
1、介面的定義與使用
(1)介面中的變數會被隱式地指定為public static final變數(並且只能是public static final變數,用private修飾會報編譯錯誤)。接口裡的資料成員必須初始化
,常見的是全域性變數。
(2)介面中的方法會被隱式地指定為public abstract方法且只能是public abstract方法(用其他關鍵字,比如private、protected、static、 final等修飾會報編譯錯誤)。也就是說,介面不能像抽象類一樣定義一般的方法,需定義“抽象方法”。
(3) 另,Java8中為避免在介面中新增新方法後要修改所有實現類,允許定義預設方法,即default方法,也可以稱為Defender方法,或者虛擬擴充套件方法(Virtual extension methods)。
Default方法是指,在介面內部包含了一些預設的方法實現(也就是介面中可以包含方法體
(4)介面中不能含有靜態程式碼塊以及靜態方法(抽象類中可以有靜態程式碼塊和靜態方法)。
(5)在Java中使用interface關鍵字來定義一個介面。
介面定義的語法如下:
interface 介面名稱 {
final 資料型別 成員名 = 常量; // 資料成員必須賦初值
abstract 返回值的資料型別 方法名(引數...); // 抽象方法
default 返回值的資料型別 方法名(引數...) { // 預設方法,包含方法體
// ... 方法體
}
}
定義一個介面例項:
interface A {
public static final String INFP = "Hello,world!"; // 全域性常量
public abstract void print(); // 抽象方法
}
帶預設方法的介面定義例項:
interface A {
public static final String INFP = "Hello,world!"; // 全域性常量
public abstract void print(); // 抽象方法
default public void otherPrint(){
System.out.println("default methods!");
}
}
雖然有了介面,可是定義的介面A和介面B因裡面存在抽象方法,都不能被使用者直接使用。
(6)介面必須有子類,子類依靠implements關鍵字可以同時實現多個介面。
(7)介面的子類(如果不是抽象類)則必須覆寫介面之中的全部抽象方法。
(8)介面可以利用物件多型性,利用子類實現物件的例項化。
(9)介面與一般類一樣,本身也具有資料成員與方法,但資料成員一定要賦初值,且此值不能再更改,方法也必須是“抽象方法”或default方法。
也正因為介面中的方法除default方法外必須是抽象方法,而沒有一般的方法,所以介面定義格式中,抽象方法宣告的關鍵字abstract是可以省略的。
同理,介面的資料成員身上,因資料成員必須賦初值,且此值不能再被更改,所以宣告資料成員的關鍵字final也可省略。
例:
interface A {
public static String INFP = "Hello,world!"; // 全域性常量,省略final
public void print(); // 抽象方法,省略abstract
default public void otherPrint(){
System.out.println("default methods!");
}
}
(10)在Java中介面是用於實現多繼承的一種機制,也是Java設計中最重要的一個環節,每一個由介面實現的類必須在類內部覆寫介面中的抽象方法,且可自由地使用介面中的常量。
既然接口裡只有抽象方法,它只需宣告而不用定義處理方式,於是自然可以聯想到介面沒有辦法像一般類一樣,再用它來建立物件。利用介面建立新類的過程,稱之為介面的實現(implementation)。
介面實現的語法:
class 類名 implements 介面A,介面B... {
...
}
帶default方法介面的實現:
interface InterfaceA {
public static String INFO = "static final"; // 全域性常量,省略final
public void print(); // 抽象方法,省略abstract
default public void otherPrint() {
System.out.print("Print default1 method InterfaceA!");
}
}
class InterfaceAB implements InterfaceA {
@Override
public void print() {
System.out.print("Print abstract methods InterfaceA!");
System.out.print(INFO);
}
}
public class InterfaceDefault {
public static void main(String[] args) {
InterfaceAB ab = new InterfaceAB();
ab.print(); // 呼叫覆寫過的抽象方法
ab.otherPrint(); // 呼叫介面中的預設方法
System.out.print(InterfaceA.INFO); // 輸出介面中的常量
}
}
【結果】
(11)Java 8 中允許介面中只定義預設方法,無抽象方法。
interface InterfaceA {
default public void otherPrint() {
System.out.print("Print default1 method InterfaceA!");
}
}
class InterfaceAB implements InterfaceA {}
public class InterfaceDefault {
public static void main(String[] args) {
InterfaceAB ab = new InterfaceAB();
ab.otherPrint(); // 呼叫介面中的預設方法
}
}
【結果】
上例中定義了僅有一個預設方法的介面,無抽象方法,繼承介面的子類因不需覆寫抽象方法,內容為空。
介面與抽象類相比,最大的區別就在於子類上,子類可以同時實現多個介面。
例:
interface A {
public static String INFO = "Hello,world!";
public void print();
}
interface B {
public void get();
}
class X implements A,B {
public void print() {
System.out.println(INFO);
}
public void get() {
System.out.println("你好!");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
X x = new X(); // 例項化子類物件
A a = x; // 為父介面例項化
B b = x; // 為父介面例項化
a.print();
b.get();
}
}
【結果】
(12)一個類實現多個介面時,若介面中有預設方法,不能出現同名預設方法。
但在Java8中,如果一個類實現兩個或多個介面,即多繼承,但是若其中兩個介面中都包含一個名字相同的default方法,如下例中的InterfaceA,InterfaceB,有同名的預設方法DefaultMethod(),但方法體不同。
interface A {
public void someMethod();
default public void defaultMethod() {
System.out.println("Default method implementation in the interface A");
}
}
interface B {
default public void defaultMethod() {
System.out.println("Default method implementation in the interface B");
}
}
class X implements A,B {
public void someMethod() {
System.out.println("Some methods implementation in the class!");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
X x = new X(); // 例項化子類物件
x.someMethod();
x.defaultMethod(); // 錯誤,
}
}
【結果】
如果編譯以上的程式碼,編譯器會報錯,因為編譯器不知道應該在兩個同名的default方法中選擇哪一個,因此產生了二義性。
(13)多繼承中,如果說在一個子類即要實現介面又要繼承抽象類,則應該採用先繼承後實現的順序完成。
interface A {
String INFO = "Hello,world!";
public void print();
}
interface B {
public void get();
}
abstract class C {
public abstract void fun();
}
class X extends C implements A,B { // 先繼承,後實現
public void print() {
System.out.println(INFO);
}
public void get() {
System.out.println("你好!");
}
public void fun() {
System.out.println("你好!JAVA");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
X x = new X(); // 例項化子類物件
A a = x; // 為父介面例項化
B b = x; // 為父介面例項化
C c = x; // 為抽象類例項化
a.print();
b.get();
c.fun();
}
}
【結果】
(14)介面使用過程中,一個抽象類可以繼承多個介面,但是反過來講,一個介面卻不能夠繼承抽象類,但一個介面卻可以使用extends關鍵字繼承多個介面,也可以同時繼承多個介面的抽象方法與常量。
interface A {
String INFO = "Hello,world!";
public void print();
}
interface B {
public void get();
}
abstract class C implements A,B {
public abstract void fun();
}
interface D extends A,B { // 同時繼承兩個介面
public void printD();
}
class X extends C implements D { // 先繼承,後實現
public void print() {
System.out.println(INFO);
}
public void get() {
System.out.println("你好!");
}
public void fun() {
System.out.println("抽象類C實現介面A,B!");
}
public void printD() {
System.out.println("抽象類D繼承兩個介面A,B!");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
X x = new X(); // 例項化子類物件
A a = x; // 為父介面例項化
B b = x; // 為父介面例項化
C c = x; // 為抽象類例項化
D d = x; // 為父介面例項化
a.print();
b.get();
c.fun();
d.printD();
}
}
【結果】