1. 程式人生 > >Java之路:介面

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方法是指,在介面內部包含了一些預設的方法實現(也就是介面中可以包含方法體

,這打破了Java之前版本對介面的語法限制),從而使得介面在進行擴充套件的時候,不會破壞與介面相關的實現類程式碼。

(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();
	}
}

【結果】
在這裡插入圖片描述