定義接口
接口是從多個相似類中抽象出來的規範,接口不提供任何實作。從某個角度看,接口可被當成一個特殊類,是以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());
}
}