抽象方法:這種方法只有聲明而沒有方法體,下面是抽象方法生命所採用的語法java
abstract void f();
包含抽象方法的類叫作抽象類,若是一個類包含一個或多個抽象方法,該類必須被限定爲抽象的,而且編譯器不會容許直接建立一個抽象類對象,正確的作法是從這個抽象類繼承併爲抽象方法完成定義,這樣就能夠建立這個類的對象。但若是導出類還有抽象方法,那這個類還應該加上abstract聲明爲抽象類。簡單的使用以下設計模式
package tij.interfacedemo; public class Test { public static void main(String[] args) { new Wind().play(Note.MIDDLE_A); } } enum Note{ MIDDLE_A,MIDDLE_B,MIDDLE_C; } abstract class Instrument{//抽象父類 private int i;// public abstract void play(Note n); public String what(){ return "Instrument"; } public abstract void adjust(); } class Wind extends Instrument{ public void play(Note n){ System.out.println("Wind.play() "+n); } public String what(){ return "wind"; } public void adjust(){ } }
其實能夠發現和普通繼承沒什麼區別。api
接口(interface)是一個徹底抽象的類,沒有任何具體實現方法,容許建立者建立方法的方法名、參數列表以及返回類型,但沒有任何方法體。接口體現的思想是:「實現了這個接口的類看起來都像這樣」。而且接口具備繼承的一系列特色,如向上轉型等等。
接口能夠加public關鍵字(若是要加也只能加public,不能加private和protected),不添加就是默認訪問權限(包訪問權限)。接口中的方法是自動是public abstract的。接口也能夠包含域(即引用變量或基本變量),而且自動是static final的,而且也不能被private和protected修飾。以下例:app
package tij.interfacedemo; public class Test { public static void main(String[] args) { new Wind().play(Note.MIDDLE_A); } } enum Note{ MIDDLE_A,MIDDLE_B,MIDDLE_C; } interface Instrument{// int i=5;// void play(Note n); String what(); void adjust(); } class Wind implements Instrument{ public void play(Note n){ System.out.println("Wind.play() "+n); } public String what(){ return "wind"; } public void adjust(){ } }
這是接口的一個很好的功能
在繼承中,若是一個方法接受一個類的實例做爲參數,那麼你能夠用這個類或子類的實例當作傳入參數,以下例:dom
package tij.interfacedemo; import java.util.Arrays; public class Test { static void process(Processor p, Object s) { System.out.println("Using Processor:" + p.name()); System.out.println(p.process(s)); } static String s = "Disagreement with beliefs is by definition incorrect"; public static void main(String[] args) { process(new Upcase(), s); process(new Downcase(), s); process(new Splitter(), s); } } class Processor { public String name() { return getClass().getSimpleName(); } Object process(Object input) { return input; } } class Upcase extends Processor { String process(Object input) { return ((String) input).toUpperCase(); } } class Downcase extends Processor { String process(Object input) { return ((String) input).toLowerCase(); } } class Splitter extends Processor { String process(Object input) { return Arrays.toString(((String) input).split(" ")); } }
在本例中,Test.process方法能夠接受一個Processor以及其子類的實例對象,而後對一個Object的對象s進行操做,根據傳入的Processor不一樣,進行的操做也不一樣,這種方法體現了策略設計模式,這類方法包含要執行的固定部分(s),策略包含變化的部分(p)。可是在這個例子中要注意兩個與本章不相關的事兒:1.應該想一想爲何子類明明沒有重寫name方法,但輸出卻仍是像重寫了同樣。2.子類重寫了process方法,但返回值不是Object而是String,重寫方法必需要是與類方法的返回類型的相同或者是其子類。this
可是假如如今咱們發現了一系列濾波器類,以下:設計
class Waveform{//表明波形 private static long counter; private final long id=counter++; public String toString(){ return "Waveform"+id; } } class Filter{//濾波器 public String name(){ return getClass().getSimpleName(); } public Waveform process(Waveform input){ return input; } } class LowPass extends Filter{ double cutoff;//設定低通濾波器的濾波上限 public LowPass(double cutoff){ this.cutoff=cutoff; } public Waveform process(Waveform input){ return input; } } class HighPass extends Filter{ double cutoff;//設置高通濾波器的濾波下限 public HighPass(double cutoff){ this.cutoff=cutoff; } public Waveform process(Waveform input){ return input; } } class BandPass extends Filter{ double lowCutoff,highCutoff;//設置帶通濾波器的濾波上下限 public BandPass(double lowCut,double highCut){ this.lowCutoff=lowCut; this.highCutoff=highCut; } public Waveform process(Waveform input){ return input; } }
那麼若是想把各類濾波器傳給Test.process方法,那這會被編譯器阻止,由於process方法只接受processor類以及子類,那若是但願運用了策略設計模式的Test.process方法仍能接受濾波器,那麼首先就須要把processor改變成接口:code
interface Processor { String name() ; Object process(Object input) ; } abstract class StringProcessor implements Processor{ public String name(){ return getClass().getSimpleName(); } } class Upcase extends StringProcessor { public String process(Object input) { return ((String) input).toUpperCase(); } } class Downcase extends StringProcessor { public String process(Object input) { return ((String) input).toLowerCase(); } } class Splitter extends StringProcessor { public String process(Object input) { return Arrays.toString(((String) input).split(" ")); } } class Waveform{//表明波形 private static long counter; private final long id=counter++; public String toString(){ return "Waveform"+id; } }
但接下來咱們發現,濾波器這個類是咱們找到的,咱們並不能對這麼個類內的代碼進行修改,如何讓新的Test.process還能接受濾波器呢,因而咱們能夠採用適配器設計模式,代碼以下:orm
class FilterAdapter implements Processor { Filter filter; public FilterAdapter(Filter filter) { this.filter = filter; } public String name() { return filter.name(); } public Waveform process(Object input) { return filter.process((Waveform) input); } }
這樣傳進去這個FilterAdapter適配器就OK了對象
接口的另外一個重要的功能就是能實現多重繼承
package tij.interfacedemo; public class Test { public static void main(String[] args) { Hero superman=new Hero(); superman.fight(); superman.fly(); superman.swim(); } } class ActionCharacter { public void fight() { System.out.println("fight"); } } interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void fly() { System.out.println("fly"); } public void swim() { System.out.println("swim"); } }
經過繼承能夠生成一個新的接口,以此來對原來的接口進行拓展;還能夠經過繼承在新接口中組合多個接口(玩的真花= =)。以下:
interface Monster { void menace(); } interface DangerousMonster extends Monster { void destroy(); } interface Lethal { void kill(); } class DragonZilla implements DangerousMonster { public void menace() {} public void destroy() {} } interface Vampire extends DangerousMonster, Lethal { void drinkBlood(); } class VeryBadVampire implements Vampire { public void destroy() {} public void menace() {} public void kill() {} public void drinkBlood() {} }
接口之間能夠繼承,能夠多繼承,能夠相互拓展
在實現多重繼承時,若是不一樣接口有相同方法怎麼辦
interface I1 { void f(); } interface I2 { int f(int i); } interface I3 { int f(); } class C { public int f() { return 1; } } class C2 implements I1, I2 { public int f(int i) { return 1; } public void f() {}//重載 } class C3 extends C implements I2{ public int f(int i) {//重載 return 0; } } class C4 extends C implements I3{ //能夠沒必要重寫int f()方法,由於從C那裏繼承過來了,但C那裏的f()必須是public的 } //class C5 extends C implements I1{ // //錯誤 //} //interface I4 extends I1,I3{ // //錯誤 //}
所以在設計接口的時候請儘可能避免這點
接口的一種經常使用的方法就是以前提到的策略設計模式,如編寫一個進行某些操做的方法,而這個方法接收一些接口,就是說若是你的對象遵循個人接口那就能用。
下面的例子中使用了scanner,這個類須要接收一個readable對象,其中arg用來存儲要輸入的字符串的
import java.io.IOException; import java.nio.CharBuffer; import java.util.Random; import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner s = new Scanner(new RandomWords(10)); while (s.hasNext()) { System.out.println(s.next()); } } } class RandomWords implements Readable { private static Random rand = new Random(47); private static final char[] capitals = "ABCDEFGHIGKLMNOPQRST".toCharArray(); private static final char[] lowers = "ABCDEFGHIGKLMNOPQRST".toLowerCase() .toCharArray(); private static final char[] vowels = "aeiou".toCharArray(); private int count; public RandomWords(int count) { this.count = count; } public int read(CharBuffer arg) throws IOException { if (count-- == 0) { return -1; } arg.append(capitals[rand.nextInt(capitals.length)]); for (int i = 0; i < 4; i++) { arg.append(vowels[rand.nextInt(vowels.length)]); arg.append(lowers[rand.nextInt(lowers.length)]); } arg.append(" "); return 10;// Number of characters appended } }
接口的還有一個功能就是以前咱們提到過的適配器設計模式,在這裏再舉另外一個與scanner相關的例子。
首先假如咱們如今有一個以下的類:
class RandomDoubles{ private static Random rand =new Random(47); public double next(){ return rand.nextDouble(); } }
但願讓他做爲一個readable傳入給scanner,來生成隨機的double類型數,這須要裝飾設計模式
import java.io.IOException; import java.nio.CharBuffer; import java.util.Random; import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner s=new Scanner(new AdaptedRandomDoubles(7)); while(s.hasNext()){ System.out.println(s.next()); } } } class AdaptedRandomDoubles extends RandomDoubles implements Readable { private int count; public AdaptedRandomDoubles(int count){ this.count=count; } public int read(CharBuffer cb) throws IOException { if(count--==0){ return -1; } String result=Double.toString(this.next()); cb.append(result); return result.length(); } }
實例變量都是static final的,好告終束
推薦先看完內部類再來看這個
class t1 implements A.C,A.B{//訪問不到A.D public void f() { } } class A { interface B { void f(); } public class BImp implements B { public void f() {} } private class BImp2 implements B { public void f() {} } public interface C { void f(); } class CImp implements C { public void f() {} } private interface D { void f(); } private class DImp implements D { public void f() {} } public class DImp2 implements D { public void f() {} } }
interface E{ interface G{ //默認爲public void f(); } } class t2 implements E.G{ public void f() { } }
接口時實現多重繼承的途徑,而生成遵循某個接口的對象的典型方式就是工廠方法設計模式
package tij.interfacedemo; public class Test { public static void main(String[] args) { Factories.serviceConsumer(new Implementation1Factory()); Factories.serviceConsumer(new Implementation2Factory()); } } interface Service { void method1(); void method2(); } interface ServiceFactory { Service getService(); } class Implementation1 implements Service { Implementation1() {} public void method1() {System.out.println("Implementation1 method1");} public void method2() {System.out.println("Implementation1 method2");} } class Implementation1Factory implements ServiceFactory { public Service getService() { return new Implementation1(); } } class Implementation2 implements Service { Implementation2() {} public void method1() {System.out.println("Implementation2 method1");} public void method2() {System.out.println("Implementation2 method2");} } class Implementation2Factory implements ServiceFactory { public Service getService() { return new Implementation1(); } } class Factories{ static void serviceConsumer(ServiceFactory fact){ Service s = fact.getService(); s.method1(); s.method2(); } }
這樣設計的好處就是將方法的實現與實例對象的生成分離開來,並且在使用Factories.serviceConsumer的時候不須要特定指定是哪一種Service.