介面
介紹Java中interface的用法,及其物件導向意義。
何謂介面? What is Interface?
舉個現實中的例子,冰箱跟烤箱都是常見的電器設備,然而台灣電力公司要如何供給一般家庭所需的電力呢? 沒錯,就是110/220伏特的交流電,而且有一個標準的電力接頭,冰箱跟烤箱只需要接受這個電力規格,就可以使用,不管內部作了什麼處理,使用者只需要為他們接上制訂好的電源。
所以我們可以說,冰箱跟烤箱擁有相同的『行為』,在這裡指的就是接受並運用這個110/220伏特的交流電。
介面,描述不同類別的共通行為。
為什麼需要介面? Why Interface?
假設電器設備指的是可以從台灣電力公司取得需要的電源。
冰箱跟烤箱都可以接受台灣電力公司的電源,這兩個東西都可以視為電器設備,但這兩個東西在繼承關係上可說是相差很遠的。
例如:
物件 -> 冷藏設備 -> 冰箱。
物件 -> 加熱設備 -> 烤箱。
由於Java不允許多重繼承(任何類別只能有一個父類別),所以沒辦法讓冰箱既是冷藏設備又是電器設備。
無法多重繼承:
class 冰箱 extends 冷藏設備,電器設備{ // 編譯錯誤,不允許多重繼承
}
從現實中來看,冰箱跟烤箱只有『使用台電提供的電』這個共通的行為,因此我們把電器設備定義為介面,如此一來冰箱跟烤箱都可以『實作』這個介面,從而具有這個介面的特性,台電也很清楚的知道只要送出的電可以讓『電器設備』這個介面使用就好,任何需要電的設備只要符合這個介面制訂的規則,就可以獲得電力。
class 冰箱 extends 冷藏設備 implements 電氣設備{ // 繼承冷藏設備,實作電器設備這個介面
// 成員宣告
}
如此一來,冰箱就可以視為電器設備,當作電器設備來使用。
宣告介面 Declare interface
在Java中,我們可以把介面interface當成一種很特別的類別。
宣告方式:
[修飾子] interface 介面名稱 {
// 成員定義
}
範例程式:
public interface Power{
void getPowerFromTP();
}
介面的宣告就是使用關鍵字interface,跟類別很像都是走差不多的格式,其中方法的定義只能宣告『方法的原型』,就像在『抽象』的章節中提到的抽象方法一樣。
實作介面 implements interface
利用關鍵字implements,來讓類別實作某個介面,類別需要定義好該介面所制定的方法。
範例程式:
class Refrigerator implements Power{
public void getPowerFromTP(){
System.out.println("轉換..轉換....")
}
}
必須實作『所有』該介面宣告的方法,否則會編譯錯誤。
此時這個類別就可以被視為該介面來使用。
Power obj = new Refrigerator();
obj.getPowerFromTP();
執行結果:
轉換..轉換....
實作多個介面
在Java不允許多重繼承,但同一個類別可以實作多個介面,算是彌補了不能多重繼承所帶來的不方便。
實作多個介面用『,』隔開,寫上介面名稱,並且該類別必須實作每個介面所制定的方法。
使用格式:
class 類別名稱 implements 介面1,介面2,...介面n{
// 成員定義
}
範例程式:
interface A{
void Amethod();
}
interface B{
void Bmethod();
}
class MyClass implements A,B {
public void Amethod(){
}
public void Bmethod(){
}
}
內訂的修飾子
在interface中定義的欄位、方法都有規定好的修飾子,可以寫也可以不寫,但不能衝突。
介面方法的修飾:
public abstract 回傳型態 方法名稱();
程式設計師可以自己寫,但不能與之衝突。
interface MyInterface{
public abstract void A(); // ok
public void B(); // ok,編譯完會自行在執行檔加上 public abstract
void C(); // ok,編譯完會自行在執行檔加上 public abstract
private void D(); // no ok, 編譯錯誤,修飾子不正確
void E(){}; // no ok, 編譯錯誤,只能定義原型,不行定義方法本體
}
介面欄位的修飾:
public static final 資料型態 變數名稱 = 值;
跟方法一樣,可以省略修飾子,但不能與之衝突。
interface Qoo{
int value = 10;
public int value2 = 20;
public static int value3 = 30;
public static final int value4 = 40;
// 以上四行敘述,編譯完成後在執行檔中修飾子均為 public static final
int value5; // 編譯錯誤,必須給訂初始值
private int value6 = 60; // 編譯錯誤,private與public衝突
}
介面欄位的存取
上面提到,可以在介面中宣告資料欄位並且修飾子限定是public static final,要如何使用呢?
介面名稱.欄位名稱;
嗯,就把介面當成一種特殊的類別,就是存取靜態欄位的方法。
程式範例:
interface Power{
int value = 10;
}
class Test{
public static void main(String[] args){
System.out.println(Power.value);
}
}
執行結果:
10
要注意的是在介面中的欄位都是public static final的修飾,所以不能改變其值,一般都是當作該介面的常數來使用。
同名欄位的存取
一個類別可以實作多個介面,最多繼承一個類別,所以加上自己定義的欄位,可能會有許多相同名字的變數,該如何存取?
interface Inter1 {
int value = 10;
}
interface Inter2 {
int value = 20;
}
class Father{
int value = 30;
}
class A extends Father implements Inter1,Inter2{
int value = 40;
}
存取每個同名變數的範例程式:
class Test {
public static void main(String[] args) {
A a = new A();
System.out.println( Inter1.value ); // 以介面名稱存取,因為是static修飾
System.out.println( Inter2.value ); // 同上
System.out.println( ((Father)a).value ); // 先把物件a轉型成該父類別,再存取
System.out.println( a.value ); // 直接以物件存取
}// end of main(String[])
}// end of class Test
執行結果:
10
20
30
40
同名方法的實作
一個類別可以實作多個介面,但介面中如果有相同的方法呢?
interface A{
void method();
}
interface B{
void method();
int method(int a);
}
class MyClass implements A,B{
public int method(int a) {
//...
}
public void method() {
//...
}
}
根據方法的多載,相同名稱、不同參數即視為不同的方法,一模一樣的方法實作一個即可,關鍵點是每個不同的方法都必須實作。
介面的繼承
沒錯,介面也可以繼承,而且還允許多重繼承!
interface 介面名稱 extends 介面1,介面2,...,介面n{
}
彼此繼承的結果就是,實作該介面的類別必須實作每個定義的方法。
程式範例:
interface A{
void a();
}
interface B{
void b();
}
interface C extends A,B{ // 介面的繼承,繼承多個介面以逗號『,』隔開
void c();
}
class MyClass implements C{ // 必須實作介面C及其所有父類別定義的方法
public void a() {
}
public void b() {
}
public void c() {
}
}
抽象類別實作介面
抽象類別也是個類別,當然也可以實作介面。
然而抽象類別中可以定義該介面宣告的方法的本體,也可以不定義。沒定義的話就是由繼承這個抽象類別的子類別要實作所有抽象方法。
程式範例:
interface A{
void a();
void b();
}
abstract class AbsClass implements A{
public void b(){
System.out.println("hello b~");
}
abstract void c();
}
class MyClass extends AbsClass{
public void a() {
}
// 方法b()已經在AbsClass實作,MyClass不需要再實作,當然也可以再覆寫b()
public void c() {
}
}
原則就是,非抽象類別要實作所有未定義的方法。
抽象類別與介面的比較 Abstract Classes Compared to Interfaces
抽象類別與介面有點像,兩個都不行被實體化成物件。
抽象類別
用於被繼承,子類別要實作定義的抽象方法。
抽象類別中可以定義完整的方法(方法本體),也可以只定義方法原型。
可以定義完整的資料欄位供繼承類別使用。
設計中心以資料為主體。
介面
用於被實作,子類別要實作定義的方法。
介面中只能定義方法原型,不能有方法本體。
方法的修飾子必為public abstract,欄位的修飾子必為public static final,可省略不可衝突。
定義的資料欄位用於作為常數使用。(因為修飾子為public static final)
設計中心以方法(行為)為主體。
一般來說有共同的概念可以繼承相同的抽象父類別,
若只是行為相同以介面來設計會比較恰當。
實務上先考慮介面的劃分會比較方便,畢竟類別可以繼承多個介面,需要用到層層的欄位概念再使用類別去繼承。
Last updated
Was this helpful?