1. 程式人生 > >Java學習筆記(31)--介面 詳解(一)

Java學習筆記(31)--介面 詳解(一)

一、基本概念

介面(Interface),在JAVA程式語言中是一個抽象型別,是抽象方法的集合。介面通常以interface來宣告。一個類通過繼承介面的方式,從而來繼承介面的抽象方法。

如果一個類只由抽象方法和全域性常量組成,那麼這種情況下不會將其定義為一個抽象類。只會定義為一個介面,所以介面嚴格的來講屬於一個特殊的類,而這個類裡面只有抽象方法和全域性常量,就連構造方法也沒有。

範例:定義一個介面

interface A{//定義一個介面

    public static final String MSG = "hello";//全域性常量
    public abstract void
print();//抽象方法 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二、介面的使用

1、由於接口裡面存在抽象方法,所以介面物件不能直接使用關鍵字new進行例項化。介面的使用原則如下: 
(1)介面必須要有子類,但此時一個子類可以使用implements關鍵字實現多個介面; 
(2)介面的子類(如果不是抽象類),那麼必須要覆寫介面中的全部抽象方法; 
(3)介面的物件可以利用子類物件的向上轉型進行例項化。

範例:

package com.wz.interfacedemo;

interface A{//定義一個介面A

    public static final String MSG = "hello";//全域性常量
public abstract void print();//抽象方法 } interface B{//定義一個介面B public abstract void get(); } class X implements A,B{//X類實現了A和B兩個介面 @Override public void print() { System.out.println("介面A的抽象方法print()"); } @Override public void get() { System.out.println("介面B的抽象方法get()"
); } } public class TestDemo { public static void main(String[] args){ X x = new X();//例項化子類物件 A a = x;//向上轉型 B b = x;//向上轉型 a.print(); b.get(); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

執行結果:

介面A的抽象方法print()
介面B的抽象方法get()
  • 1
  • 2

以上的程式碼例項化了X類的物件,由於X類是A和B的子類,那麼X類的物件可以變為A介面或者B介面物件。我們把測試主類程式碼改一下:

public class TestDemo {

    public static void main(String[] args){

        A a = new X();

        B b = (B) a;
        b.get();

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

執行結果:

介面B的抽象方法get()
  • 1

好,沒任何問題,我們再來做個驗證:

public class TestDemo {

    public static void main(String[] args){

        A a = new X();

        B b = (B) a;
        b.get();

        System.out.println(a instanceof A);
        System.out.println(a instanceof B);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

執行結果:

介面B的抽象方法get()
true
true
  • 1
  • 2
  • 3
  • 4

我們發現,從定義結構來講,A和B兩個介面沒有任何直接聯絡,但這兩個介面卻擁有同一個子類。我們不要被型別和名稱所迷惑,因為例項化的是X子類,而這個類物件屬於B類的物件,所以以上程式碼可行,只不過從程式碼的編寫規範來講,並不是很好。

2、對於子類而言,除了實現介面外,還可以繼承抽象類。若既要繼承抽象類,同時還要實現介面的話,使用一下語法格式:

class 子類 [extends 父類] [implemetns 介面1,介面2,...] {}
  • 1

範例:

interface A{//定義一個介面A

    public static final String MSG = "hello";//全域性常量

    public abstract void print();//抽象方法
}

interface B{//定義一個介面B

    public abstract void get();
}

abstract class C{//定義一個抽象類C
    public abstract void change();
}

class X extends C implements A,B{//X類繼承C類,並實現了A和B兩個介面

    @Override
    public void print() {
        System.out.println("介面A的抽象方法print()");
    }

    @Override
    public void get() {
        System.out.println("介面B的抽象方法get()");
    }

    @Override
    public void change() {
        System.out.println("抽象類C的抽象方法change()");

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

對於介面,裡面的組成只有抽象方法和全域性常量,所以很多時候為了書寫簡單,可以不用寫public abstract 或者public static final。並且,介面中的訪問許可權只有一種:public,即:定義介面方法和全域性常量的時候就算沒有寫上public,那麼最終的訪問許可權也是public,注意不是default。以下兩種寫法是完全等價的:

interface A{
    public static final String MSG = "hello";
    public abstract void print();
}
  • 1
  • 2
  • 3
  • 4

等價於

interface A{
    String MSG = "hello";
    void print();
}
  • 1
  • 2
  • 3
  • 4

但是,這樣會不會帶來什麼問題呢?如果子類子類中的覆寫方法也不是public,我們來看:

package com.wz.interfacedemo;

interface A{

    String MSG = "hello";

    void print();
}

class X implements A{

    void print() {
        System.out.println("介面A的抽象方法print()");
    }

}

public class TestDemo {
    public static void main(String[] args){

        A a = new X();
        a.print();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

執行結果:

Exception in thread "main" java.lang.IllegalAccessError: com.wz.interfacedemo.X.print()V
    at com.wz.interfacedemo.TestDemo.main(TestDemo.java:22)
  • 1
  • 2

這是因為介面中預設是public修飾,若子類中沒用public修飾,則訪問許可權變嚴格了,給子類分配的是更低的訪問許可權。所以,在定義介面的時候強烈建議在抽象方法前加上public ,子類也加上:

interface A{

    String MSG = "hello";

    public void print();
}

class X implements A{

    public void print() {
        System.out.println("介面A的抽象方法print()");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3、在Java中,一個抽象類只能繼承一個抽象類,但一個介面卻可以使用extends關鍵字同時繼承多個介面(但介面不能繼承抽象類)。

範例:

interface A{
    public void funA();
}

interface B{
    public void funB();
}

//C介面同時繼承了A和B兩個介面
interface C extends A,B{//使用的是extends
    public void funC();
}

class X implements C{

    @Override
    public void funA() {


    }

    @Override
    public void funB() {


    }

    @Override
    public void funC() {


    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

由此可見,從繼承關係來說介面的限制比抽象類少: 
(1)一個抽象類只能繼承一個抽象父類,而介面可以繼承多個介面; 
(2)一個子類只能繼承一個抽象類,卻可以實現多個介面(在Java中,介面的主要功能是解決單繼承侷限問題)

4、從介面的概念上來講,介面只能由抽象方法和全域性常量組成,但是內部結構是不受概念限制的,正如抽象類中可以定義抽象內部類一樣,在介面中也可以定義普通內部類、抽象內部類和內部介面(但從實際的開發來講,使用者自己去定義內部抽象類或內部介面的時候是比較少見的),範例如下,在介面中定義一個抽象內部類:

interface A{
    public void funA();

    abstract class B{//定義一個抽象內部類
        public abstract void funB();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在介面中如果使用了static去定義一個內介面,它表示一個外部介面:

interface A{
    public void funA();

    static interface B{//使用了static,是一個外部介面
        public void funB();
    }
}
class X implements A.B{

    @Override
    public void funB() {

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

三、介面的實際應用(標準定義)

在日常的生活之中,介面這一名詞經常聽到的,例如:USB介面、列印介面、充電介面等等。 
interface

如果要進行開發,要先開發出USB介面標準,然後裝置廠商才可以設計出USB裝置。

現在假設每一個USB裝置只有兩個功能:安裝驅動程式、工作。 
定義一個USB的標準:

interface USB {   // 操作標準       
    public void install() ;
    public void work() ;
}
  • 1
  • 2
  • 3
  • 4

在電腦上應用此介面:

class Computer {
   public void plugin(USB usb) {
          usb.install() ;
          usb.work() ;
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定義USB裝置—手機:

class Phone implements USB {
     public void install() {
           System.out.println("安裝手機驅動程式。") ;
     }
     public void work() {
           System.out.println("手機與電腦進行工作。") ;
     }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

定義USB裝置—印表機:

class Print implements USB {
      public void install() {
           System.out.println("安裝印表機驅動程式。") ;
      }
      public void work() {
           System.out.println("進行檔案列印。") ;
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

定義USB裝置—MP3:

class MP3 implements USB {
      public void install() {
           System.out.println("安裝MP3驅動程式。") ;
      }
      public void work() {
           System.out.println("進行MP3拷貝。") ;
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

測試主類:

public class TestDemo {
    public static void main(String args[]) {
        Computer c = new Computer() ;
        c.plugin(new Phone()) ;
        c.plugin(new Print()) ;
        c.plugin(new MP3());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

執行結果:

安裝手機驅動程式。
手機與電腦進行工作。
安裝印表機驅動程式。
進行檔案列印。
安裝MP3驅動程式。
進行MP3拷貝。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看出,不管有多少個USB介面的子類,都可以在電腦上使用。 
在現實生活中,標準的概念隨處可見,而在程式裡標準使用介面定義的。

未完待續。。。