天天看點

Java學習筆記一面向對象接口

定義接口

接口是從多個相似類中抽象出來的規範,接口不提供任何實作。從某個角度看,接口可被當成一個特殊類,是以Jva源檔案裡最多隻能有一個public接口,如果一個Java源檔案裡定義了一個public接口,則該源檔案的主檔案名必須與該接口名相同。接口完全支援多繼承,子接口擴充某個父接口,将會獲得父接口裡定義的是以抽象方法、常量。

[修飾符] interface 接口名 extends 父接口1, 父接口2...
{
  零個到多個常量定義...
  零個到多個抽象方法定義...
  零個到多個私有方法、預設方法或類方法定義...
  零個到多個内部類、接口、枚舉定義...  
}      

修飾符可以是public或者省略,如果省略了public通路控制符,則預設采用包權限通路控制符,即隻有在相同包結構下才可以通路該接口。一個接口可以有多個直接父接口,但接口隻能繼承接口,不能繼承類。

由于接口定義的是一種規範,是以接口裡不能包含構造器和初始化塊定義。接口裡可以包含成員變量(隻能是靜态常量)、方法(隻能是抽象執行個體方法、類方法、預設方法或私有方法)、内部類(包括内部接口、枚舉)。

接口中定義成員變量時,不管是否使用public static final修飾符,接口裡的成員變量總是使用這三個修飾符來修飾。而且接口裡沒有構造器和初始化塊,是以接口裡定義的成員變量隻能在定義時指定預設值。

// 系統自動為接口裡定義的成員變量增加public static final修飾符
// 可以省略通路控制修飾符,因為接口裡的常量隻能是public
int MAX_SIZE = 50;
public static final int MAX_SIZE = 50;      

如果不是定義預設方法、類方法或私有方法,系統将自動為普通方法增加abstract修飾符;定義接口裡的普通方法時不管是否使用public abstract修飾符,接口裡的普通方法總是使用public abstract修飾符。接口裡的普通方法不能有方法實作(方法體)。

Java 9為接口增加了一種新的私有方法,私有方法的作用就是作為工具方法,為接口中的預設方法或類方法提供支援。私有方法可以擁有方法體,但私有方法不能使用default修飾。私有方法可以使用static修飾,也就是說,私有方法既可以是類方法,也可以是執行個體方法。​

​private void test() {} 私有成員方法 或 private static void test() {} 私有類方法​

​ 必須有方法體。

在接口中定義預設方法,需要用default修飾,不能使用static修飾,且總是以public修飾,如果沒有指定,系統會自動添加public ​

​default void test() {}​

​ 必須有方法體。

類方法使用static修飾,不能使用default修飾,無論程式是否指定,類方法總是public修飾,如果開發者沒有指定public,系統會自動為類方法添加public修飾符,必須有方法體。

接口裡定義的内部類、内部接口、内部枚舉預設采用public static兩個修飾符,不管定義時是否指定這兩個修飾符,系統都會自動使用public static對它們進行修飾。

public interface Output
{
  //接口裡定義的成員變量隻能是常量
  int MAX_CACHE_LINE = 50;
  //接口裡定義的普通方法隻能是public的抽象方法
  void out();
  void getData(String msg);
  //在接口中定義預設方法,需要使用default修飾
  default void print(String.. msg)
  {
    for(String msg:msgs)
      System.out.println(msg);
  }
  //在接口中定義預設方法,需要使用default修飾
  default void test()
  {
    System.out.println("預設的test方法");
  }
  //在接口中定義類方法,需要使用static修飾
  static String staticTest()
  {
    return "接口裡的類方法";
  }
  //定義私有方法
  private void foo()
  {
    System.out.println("foo私有方法");
  }
  //定義私有靜态方法
  private static void bar()
  {
    System.out.println("bar私有靜态方法");
  }
}      

接口裡定義内部類預設使用public static修飾,也就是說接口内部類隻能是靜态内部類。如果為接口内部類指定通路控制符,則隻能指定public通路控制符;如果定義接口内部類時省略通路控制符,則該内部類預設是public通路控制權限。

接口裡可以定義内部接口,系統預設添加public static修飾符。如果定義接口裡的内部接口時指定通路控制符,則隻能使用public修飾符。

使用接口

接口不能用于建立執行個體,但接口可以用于聲明引用類型變量。當使用接口來聲明引用類型變量時,這個引用類型變量必須引用到其實作類的對象。一個類實作了一個或多個接口之後,這個類必須完全實作這些接口裡所定義的全部抽象方法;否則,該類将保留從父接口那裡繼承到的抽象方法,該類也必須定義成抽象類。

[修飾符] class 類名 extends 父類 implements 接口1, 接口2...
{
  類體
}      

實作接口方法時,必須使用public通路控制修飾符,因為接口裡的方法都是public的,而子類(相當于實作類)重寫父類方法時通路權限隻能更大或者相等,是以實作類實作接口裡的方法時隻能使用public通路權限。

//定義一個Product接口
interface Product
{
  int getProduceTime();
}
//讓Printer類實作Output和Product接口
public class Printer implement Output, Product
{
  private String[] printData = new String[MAX_CACHE_LINE]; 
  //用以記錄目前需列印的作業數
  private int dataNum = 0;
  //接口Output的抽象方法的實作
  public void out()
  {
    //隻要還有作業,就繼續列印
    System.out.println("列印機列印:"+printData[0]);
    //把作業隊列整體前移一位,并将剩下的作業數減一
    System.arraycopy(printData,1,printData,0--dataNum);
  }
  public void getData(String msg)
  {
    if(dataNum >= MAX_CACHE_LINE)
      System.out.println("輸出隊列已滿");
    else
      printData[dataNum++] = msg;
  }
  //接口Product的抽象方法的實作
  public int getProduceTime() { return 45; }
  public static void main(String[] args)
  {
    Output o = new Printer();
    o.getData("helloworld");
    o.getData("hello");
    o.out();
    o.getData("world");
    o.getData("wow");
    o.out();
    o.print("孫","悟","空");
    o.test();
    Product p = new Printer();
    System.out.println(p.getProduceTime());
    //所有接口類型的引用變量都可直接賦給Object類型的變量
    Object obj = p;
  }
}      

接口不能顯式繼承任何類,但所有接口類型的引用變量都可以直接賦給Object類型的引用變量。上面程式把Product類型的變量直接賦給Object類型變量,這是利用向上轉型來實作的。因為編譯器知道任何Java對象都必須是Object或其子類的執行個體,Product類型的對象也不例外(它必須是Product接口實作類的對象,該實作類肯定是Object的顯式或隐式子類)。

面向接口程式設計

簡單工廠模式

Computer類可以組合一個Output,可以用不同類來替換,如Printer和BetterPrinter,将輸出裝置分離,隻和Output接口耦合。

public class Computer
{
  private Output out;
  public Computer(Output out)
  {
    this.out = out;
  }
  //模拟擷取字元串輸入的方法
  public void keyIn(String msg)
  {
    out.getData(msg);
  }
  //模拟列印的方法
  public void print()
  {
    out.out();
  }
}      

Computer類不再負責建立Output對象,這裡提供一個工廠類來生成Output對象。

public class OutputFactory
{
  public Output getOutput()
  {
    return new Printer();
  }
  public static void main(String[] args)
  {
    OutputFactory of = new OutputFactory();
    Computer c = new Computer(of.getOutput());
    c.keyIn("Hello");
    c.keyIn("World");
    c.print();
  }
}      

指令模式

public interface Command
{
  //接口裡定義的process方法用于封裝處理行為
  void process(int[] target);
}
// 兩種實作
public interface PrintCommand implements Command
{
  void process(int[] target){
    for(int tmp:target)
      System.out.println("疊代輸出目标數組的元素:"+tmp);
  }
}
public interface AddCommand implements Command
{
  void process(int[] target){
    int sum = 0;
    for(int tmp:target)
      sum += tmp;
    System.out.println("疊代輸出目标數組的元素:"+sum);
  }
}      
public class ProcessArray
{
  public void process(int[] target, Command cmd)
  {
    cmd.process(target);
  }
}
public class CommandTest
{
  public static void main(String[] args)
  {
    ProcessArray pa = new ProcessArray();
    int[] target = {3, -4, 6, 4};
    pa.process(target, new PrintCommand());
    pa.process(target, new AddCommand());
  }
}