think-in-java(9)接口
生活随笔
收集整理的這篇文章主要介紹了
think-in-java(9)接口
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【9】接口
【9.1】抽象類和抽象方法
1)抽象方法:僅有方法聲明而沒有方法體;由abstract 修飾的方法;
2)抽象類:如果一個類包含一個或多個抽象方法, 則該類聲明為抽象類,由 abstract修飾;
3)當(dāng)然了,也可以創(chuàng)建一個沒有抽象方法但被abstract修飾的抽象類;
【荔枝】抽象類和抽象方法
/*public enum Note {MIDDLE_C, C_SHARP, B_FLAT; } */ //荔枝 抽象類和抽象方法 // 抽象類 abstract class Instrument {private int i; // Storage allocated for eachpublic abstract void play(Note n); // 抽象方法public String what() {return "Instrument";}public abstract void adjust(); // 抽象方法 }class Wind extends Instrument { // 抽象類子類public void play(Note n) {print("Wind.play() " + n);}public String what() {return "Wind";}public void adjust() {} }class Percussion extends Instrument { // 抽象類子類public void play(Note n) {print("Percussion.play() " + n);}public String what() {return "Percussion";}public void adjust() {} }class Stringed extends Instrument { // 抽象類子類public void play(Note n) {print("Stringed.play() " + n);}public String what() {return "Stringed";}public void adjust() {} }class Brass extends Wind { // 抽象類子類public void play(Note n) {print("Brass.play() " + n);}public void adjust() {print("Brass.adjust()");} }class Woodwind extends Wind { // 抽象類子類public void play(Note n) {print("Woodwind.play() " + n);}public String what() {return "Woodwind";} }public class Music4 { static void tune(Instrument i) {i.play(Note.MIDDLE_C);}static void tuneAll(Instrument[] e) {for (Instrument i : e)tune(i);}public static void main(String[] args) {Instrument[] orchestra = { new Wind(), new Percussion(),new Stringed(), new Brass(), new Woodwind() };tuneAll(orchestra);} } /* Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play() MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C */ 【9.2】接口
1)interface接口:產(chǎn)生了一個完全抽象的類,沒有提供任何具體實現(xiàn);
2)接口被用來建立類與類之間的協(xié)議;
3)接口與抽象類的區(qū)別:接口中的方法都必須是抽象方法,即只有方法聲明沒有方法體;而抽象類中的方法即可以是抽象方法也可以是帶有方法體的方法;
4)接口中的字段:默認被 static 和 final 修飾;訪問權(quán)限默認且必須為 public;
5)接口中的方法:其訪問權(quán)限是public,即便你不使用public修飾,其訪問權(quán)限默認且必須為 public;
6)接口的包可見性:
// 接口 interface Instrument {// Compile-time constant:int VALUE = 5; // static & final// Cannot have method definitions:void play(Note n); // Automatically publicvoid adjust(); } 【荔枝】接口
// 荔枝:接口 interface Instrument {// Compile-time constant:int VALUE = 5; // static & final// Cannot have method definitions:void play(Note n); // Automatically publicvoid adjust(); }// 實現(xiàn)類 class Wind implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Wind";}public void adjust() {print(this + ".adjust()");} }class Percussion implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Percussion";}public void adjust() {print(this + ".adjust()");} }class Stringed implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Stringed";}public void adjust() {print(this + ".adjust()");} }class Brass extends Wind {public String toString() {return "Brass";} }class Woodwind extends Wind {public String toString() {return "Woodwind";} }public class Music5 {static void tune(Instrument i) {i.play(Note.MIDDLE_C);}static void tuneAll(Instrument[] e) {for (Instrument i : e)tune(i);}public static void main(String[] args) {Instrument[] orchestra = { new Wind(), new Percussion(),new Stringed(), new Brass(), new Woodwind() };tuneAll(orchestra);} } /* Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play() MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C */ 分析)在tune() 方法中,無法判斷 Instrument 是一個普通類,抽象類,還是一個接口;
【9.3】完全解耦
【荔枝】 策略模式:創(chuàng)建一個能夠根據(jù)所傳遞的參數(shù)對象的不同而具有不同行為的方法;
(干貨——策略模式的定義和荔枝)
class Processor {public String name() { return getClass().getSimpleName(); }Object process(Object input) { return input; } }class Upcase extends Processor { // 轉(zhuǎn)大寫String process(Object input) { return ((String) input).toUpperCase(); } }class Downcase extends Processor { // 轉(zhuǎn)小寫String process(Object input) { return ((String) input).toLowerCase(); } }class Splitter extends Processor { // 分割字符串 String process(Object input) { return Arrays.toString(((String) input).split(" ")); } }public class Apply {public static void process(Processor p, Object s) {print("=== Using Processor " + p.name());print(p.process(s));}public 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);} } /* === Using Processor Upcase DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT === Using Processor Downcase disagreement with beliefs is by definition incorrect === Using Processor Splitter [Disagreement, with, beliefs, is, by, definition, incorrect] */ 分析)這類方法如process方法包含所要執(zhí)行的算法中固定不變的部分,而策略包含變化的部分;策略就是傳進去的參數(shù),它包含要執(zhí)行的代碼;
這里的話,Processor對象就是一個策略;以上荔枝中有3個不同類型的策略應(yīng)用到對字符串的處理;
【9.4】java中的多重繼承
1)普通類的單繼承和接口的多繼承: 從 一個非接口類繼承,只能繼承一個類;其余的基類必須是接口;需要把所有的接口都放置在 implements 關(guān)鍵字之后,用逗號隔開它們;
2)可以繼承多個接口,并將其轉(zhuǎn)型為每個接口;
【荔枝】java多重繼承
interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } interface CanClimb { void climb(); }// 接口多重繼承 interface MyInterface extends CanFight, CanSwim, CanFly, CanClimb { }class ActionCharacter { public void fight() { } } // 【荔枝】 java多重繼承-普通類的單繼承和接口的多繼承 class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly {public void swim() { }public void fly() { } }public class Adventure {public static void t(CanFight x) { x.fight(); }public static void u(CanSwim x) { x.swim(); }public static void v(CanFly x) { x.fly(); }public static void w(ActionCharacter x) { x.fight(); }public static void main(String[] args) {Hero h = new Hero();t(h); // Treat it as a CanFightu(h); // Treat it as a CanSwimv(h); // Treat it as a CanFlyw(h); // Treat it as an ActionCharacter} } 分析)使用接口的核心原因:為了能夠向上轉(zhuǎn)型為多個基類型,由此帶來的靈活性;
分析)第二個原因:防止客戶端程序員創(chuàng)建該類的對象,并確保這僅僅是建立一個接口;
【問題】到底是使用接口還是抽象類??接口是首選;因為靈活;
【9.5】通過繼承來擴展接口
1)擴展接口: 新接口中添加新方法聲明;通過繼承在新接口中組合多個接口;
【荔枝】擴展接口
// 【荔枝】擴展接口 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 menace() {}public void destroy() {}public void kill() {}public void drinkBlood() {} }public class HorrorShow {static void u(Monster b) { b.menace(); }static void v(DangerousMonster d) {d.menace();d.destroy();}static void w(Lethal l) { l.kill(); }public static void main(String[] args) {DangerousMonster barney = new DragonZilla();u(barney);v(barney);Vampire vlad = new VeryBadVampire();u(vlad);v(vlad);w(vlad);} } 【9.5.1】組合接口時的名字沖突
1)當(dāng)繼承的父類和實現(xiàn)的接口的方法簽名或返回類型不同,會發(fā)生聲明呢??
補充)也有可能是:?兩個父接口的方法簽名或返回類型不同; 如? :
class A extends B implements C { } class B{void f1(); } class C {int f1(); } 【荔枝】組合接口時的名字沖突
(干貨——編碼注意事項,避免不同接口中使用相同的方法名)
// 【荔枝】組合接口時的名字沖突(已修正) 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 {@Overridepublic void f() { }@Overridepublic int f(int i) { return 1; } }class C3 extends C implements I2 {@Overridepublic int f(int i) { return 1; } }class C4 extends C implements I3 {@Overridepublic int f() { return 1; } } 注意:盡量避免不同接口中使用相同的方法名,以免造成可讀性混亂;
【9.6】適配接口
1)接口最吸引人的原因:允許同一個接口具有多個不同的具體實現(xiàn);接口的常見用法是策略設(shè)計模式;
2)如果創(chuàng)建一個新類,并讓 Scanner作用于它,讓該類去實現(xiàn) Readable 接口;
【荔枝】Readable接口的實現(xiàn)類,并讓Scanner作用于該類
// 荔枝-Readable接口的實現(xiàn)類,并讓Scanner作用于該類 public class RandomWords implements Readable {private static Random rand = new Random(47);private static final char[] capitals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();private static final char[] lowers = "abcdefghijklmnopqrstuvwxyz".toCharArray();private static final char[] vowels = "aeiou".toCharArray();private int count;public RandomWords(int count) {this.count = count;}@Overridepublic int read(CharBuffer cb) {if (count-- == 0)return -1;cb.append(capitals[rand.nextInt(capitals.length)]);for (int i = 0; i < 4; i++) {cb.append(vowels[rand.nextInt(vowels.length)]);cb.append(lowers[rand.nextInt(lowers.length)]);}cb.append(" ");return 10; }public static void main(String[] args) {Scanner s = new Scanner(new RandomWords(10));while (s.hasNext())System.out.println(s.next());} } /* Yazeruyac Fowenucor Goeazimom Raeuuacio Nuoadesiw Hageaikux Ruqicibui Numasetih Kuuuuozog Waqizeyoy */ // Readable 接口 public interface Readable {public int read(java.nio.CharBuffer cb) throws IOException; } 【荔枝】通過使用interface關(guān)鍵字提供的偽多重繼承機制,可以生成既是 RandomDoubles 又是 Readable的新類
// 荔枝-通過使用 interface關(guān)鍵字提供的偽多重繼承機制 // 可以生成既是 RandomDoubles 又是 Readable的新類 public class AdaptedRandomDoubles extends RandomDoubles implements Readable {private int count;public AdaptedRandomDoubles(int count) {this.count = count;}public int read(CharBuffer cb) {if (count-- == 0)return -1;String result = Double.toString(next()) + " ";cb.append(result);return result.length();}public static void main(String[] args) {Scanner s = new Scanner(new AdaptedRandomDoubles(7));while (s.hasNextDouble())System.out.println(s.nextDouble() + " ");} } /* 0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964 */ 【9.7】接口中的域
1)接口是一種便捷的用來創(chuàng)建常量組的工具:?因為接口中的任何域都自動是 public static final ;
【荔枝】接口是一種便捷的用來創(chuàng)建常量組的工具
// 荔枝-接口是一種便捷的用來創(chuàng)建常量組的工具 // 因為接口中的任何域都自動是 public static final public class Months {int JANUARY = 1, FEBRUARY = 2, MARCH = 3, APIRL = 4, MAY = 5, JUNE = 6, JULY = 7, AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10, NOVEMBER = 11, DECEMBER = 12; } 注意) java中標識具有常量初始化值的static final時,會使用大寫字母(用下劃線分隔多個單詞);不過java se5后,建議使用 enum 關(guān)鍵字來定義枚舉變量;
【9.7.1】初始化接口中的域
1)接口中的域不能是空final,但是可以被非常量表達式來初始化;
【荔枝】使用非常量表達式來初始化接口域
// 【荔枝】使用非常量表達式來初始化接口域 public interface RandVals {Random RAND = new Random(47);int RANDOM_INT = RAND.nextInt(10);long RANDOM_LONG = RAND.nextLong() * 10;float RANDOM_FLOAT = RAND.nextLong() * 10;double RANDOM_DOUBLE = RAND.nextDouble() * 10; } 2)這些static域會在類第一次加載時被初始化,荔枝如下:
// 荔枝-測試接口static域在類第一次加載時被初始化 public class TestRandVals {public static void main(String[] args) {print(RandVals.RANDOM_INT);print(RandVals.RANDOM_LONG);print(RandVals.RANDOM_FLOAT);print(RandVals.RANDOM_DOUBLE);} } /* 8 -32032247016559954 -8.5939291E18 5.779976127815049 */
// 荔枝-接口嵌套荔枝 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 class CImp2 implements C {public void f() { }}private interface D {} // 普通類中嵌套一個接口(可以為private訪問權(quán)限) } interface E {interface G { void f(); } // 類中嵌套一個接口// Redundant "public": public interface H { void f(); } // 類中嵌套一個接口 void g();// Cannot be private within an interface: (注意:不可以為private訪問權(quán)限)// ! private interface I {} }public class NestingInterfaces {public class BImp implements A.B { // 普通類實現(xiàn)嵌套接口public void f() { }}class CImp implements A.C { // 普通類實現(xiàn)嵌套接口public void f() { }}class EImp implements E { public void g() { }}class EGImp implements E.G { // 普通類實現(xiàn)嵌套接口public void f() { }}class EImp2 implements E {public void g() {}class EG implements E.G { // 普通類實現(xiàn)嵌套接口public void f() {}}}public static void main(String[] args) {A a = new A();// Can't access A.D:// ! A.D ad = a.getD();// Doesn't return anything but A.D:// ! A.DImp2 di2 = a.getD();// Cannot access a member of the interface:// ! a.getD().f();// Only another A can do anything with getD():A a2 = new A();} } // /:~ 【注意】
注意1)嵌套接口可以擁有 public 和包可見性;
注意2)實體內(nèi)中可以嵌套private接口;而接口中不可以嵌套private接口;(干貨)
注意3)實現(xiàn)一個private接口:?那么它可以強制該接口中的方法定義不要添加任何類型信息,即無法向上轉(zhuǎn)型;
【9.9】接口與工廠
1)接口是實現(xiàn)多重繼承的途徑:?生成遵循某個接口的對象的典型方式是 工廠方法設(shè)計模式;(干貨——基于接口的工廠方法設(shè)計模式)
【荔枝】基于接口的工廠方法結(jié)構(gòu)
// 荔枝-基于接口的工廠方法結(jié)構(gòu) interface Service { void method1(); void method2(); } // 普通接口 interface ServiceFactory { Service getService(); } // 工廠接口class Implementation1 implements Service { // 實現(xiàn)普通接口的普通類Implementation1() {} public void method1() { print("Implementation1 method1"); }public void method2() { print("Implementation1 method2"); } }class Implementation1Factory implements ServiceFactory { // 實現(xiàn)工廠接口的工廠類public Service getService() { return new Implementation1(); } }class Implementation2 implements Service { // 實現(xiàn)普通接口的普通類Implementation2() {} public void method1() { print("Implementation2 method1"); }public void method2() { print("Implementation2 method2"); } }class Implementation2Factory implements ServiceFactory { // 實現(xiàn)工廠接口的工廠類public Service getService() { return new Implementation2(); } }public class Factories {public static void serviceConsumer(ServiceFactory fact) {Service s = fact.getService();s.method1();s.method2();}public static void main(String[] args) {// serviceConsumer(new Implementation1Factory()); serviceConsumer(new Implementation2Factory());} } /* Implementation1 method1 Implementation1 method2 Implementation2 method1 Implementation2 method2 */ 【荔枝】利用接口提高代碼復(fù)用率
// 【荔枝】利用接口提高代碼復(fù)用率 interface Game { // 普通接口boolean move(); }interface GameFactory { // 工廠接口Game getGame(); }class Checkers implements Game { // 實現(xiàn)普通接口的普通類private int moves = 0;private static final int MOVES = 3;public boolean move() {print("Checkers move " + moves);return ++moves != MOVES;} }class CheckersFactory implements GameFactory { // 實現(xiàn)工廠接口的工廠類public Game getGame() {return new Checkers();} }class Chess implements Game { // 實現(xiàn)普通接口的普通類private int moves = 0;private static final int MOVES = 4;public boolean move() {print("Chess move " + moves);return ++moves != MOVES;} }class ChessFactory implements GameFactory { // 實現(xiàn)工廠接口的工廠類public Game getGame() {return new Chess();} }// 工廠1 和 工廠2 復(fù)用代碼 public class Games {public static void playGame(GameFactory factory) {Game s = factory.getGame();while (s.move());}public static void main(String[] args) {playGame(new CheckersFactory()); // 工廠1playGame(new ChessFactory()); // 工廠2} } /* Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 */ 分析)如 Games 類表示一段復(fù)雜代碼,則這種方式允許你在不同類型的游戲中復(fù)用這段代碼;提高代碼復(fù)用率;
【9.1】抽象類和抽象方法
1)抽象方法:僅有方法聲明而沒有方法體;由abstract 修飾的方法;
2)抽象類:如果一個類包含一個或多個抽象方法, 則該類聲明為抽象類,由 abstract修飾;
3)當(dāng)然了,也可以創(chuàng)建一個沒有抽象方法但被abstract修飾的抽象類;
【荔枝】抽象類和抽象方法
/*public enum Note {MIDDLE_C, C_SHARP, B_FLAT; } */ //荔枝 抽象類和抽象方法 // 抽象類 abstract class Instrument {private int i; // Storage allocated for eachpublic abstract void play(Note n); // 抽象方法public String what() {return "Instrument";}public abstract void adjust(); // 抽象方法 }class Wind extends Instrument { // 抽象類子類public void play(Note n) {print("Wind.play() " + n);}public String what() {return "Wind";}public void adjust() {} }class Percussion extends Instrument { // 抽象類子類public void play(Note n) {print("Percussion.play() " + n);}public String what() {return "Percussion";}public void adjust() {} }class Stringed extends Instrument { // 抽象類子類public void play(Note n) {print("Stringed.play() " + n);}public String what() {return "Stringed";}public void adjust() {} }class Brass extends Wind { // 抽象類子類public void play(Note n) {print("Brass.play() " + n);}public void adjust() {print("Brass.adjust()");} }class Woodwind extends Wind { // 抽象類子類public void play(Note n) {print("Woodwind.play() " + n);}public String what() {return "Woodwind";} }public class Music4 { static void tune(Instrument i) {i.play(Note.MIDDLE_C);}static void tuneAll(Instrument[] e) {for (Instrument i : e)tune(i);}public static void main(String[] args) {Instrument[] orchestra = { new Wind(), new Percussion(),new Stringed(), new Brass(), new Woodwind() };tuneAll(orchestra);} } /* Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play() MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C */ 【9.2】接口
1)interface接口:產(chǎn)生了一個完全抽象的類,沒有提供任何具體實現(xiàn);
2)接口被用來建立類與類之間的協(xié)議;
3)接口與抽象類的區(qū)別:接口中的方法都必須是抽象方法,即只有方法聲明沒有方法體;而抽象類中的方法即可以是抽象方法也可以是帶有方法體的方法;
4)接口中的字段:默認被 static 和 final 修飾;訪問權(quán)限默認且必須為 public;
5)接口中的方法:其訪問權(quán)限是public,即便你不使用public修飾,其訪問權(quán)限默認且必須為 public;
6)接口的包可見性:
// 接口 interface Instrument {// Compile-time constant:int VALUE = 5; // static & final// Cannot have method definitions:void play(Note n); // Automatically publicvoid adjust(); } 【荔枝】接口
// 荔枝:接口 interface Instrument {// Compile-time constant:int VALUE = 5; // static & final// Cannot have method definitions:void play(Note n); // Automatically publicvoid adjust(); }// 實現(xiàn)類 class Wind implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Wind";}public void adjust() {print(this + ".adjust()");} }class Percussion implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Percussion";}public void adjust() {print(this + ".adjust()");} }class Stringed implements Instrument {public void play(Note n) {print(this + ".play() " + n);}public String toString() {return "Stringed";}public void adjust() {print(this + ".adjust()");} }class Brass extends Wind {public String toString() {return "Brass";} }class Woodwind extends Wind {public String toString() {return "Woodwind";} }public class Music5 {static void tune(Instrument i) {i.play(Note.MIDDLE_C);}static void tuneAll(Instrument[] e) {for (Instrument i : e)tune(i);}public static void main(String[] args) {Instrument[] orchestra = { new Wind(), new Percussion(),new Stringed(), new Brass(), new Woodwind() };tuneAll(orchestra);} } /* Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play() MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C */ 分析)在tune() 方法中,無法判斷 Instrument 是一個普通類,抽象類,還是一個接口;
【9.3】完全解耦
【荔枝】 策略模式:創(chuàng)建一個能夠根據(jù)所傳遞的參數(shù)對象的不同而具有不同行為的方法;
(干貨——策略模式的定義和荔枝)
class Processor {public String name() { return getClass().getSimpleName(); }Object process(Object input) { return input; } }class Upcase extends Processor { // 轉(zhuǎn)大寫String process(Object input) { return ((String) input).toUpperCase(); } }class Downcase extends Processor { // 轉(zhuǎn)小寫String process(Object input) { return ((String) input).toLowerCase(); } }class Splitter extends Processor { // 分割字符串 String process(Object input) { return Arrays.toString(((String) input).split(" ")); } }public class Apply {public static void process(Processor p, Object s) {print("=== Using Processor " + p.name());print(p.process(s));}public 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);} } /* === Using Processor Upcase DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT === Using Processor Downcase disagreement with beliefs is by definition incorrect === Using Processor Splitter [Disagreement, with, beliefs, is, by, definition, incorrect] */ 分析)這類方法如process方法包含所要執(zhí)行的算法中固定不變的部分,而策略包含變化的部分;策略就是傳進去的參數(shù),它包含要執(zhí)行的代碼;
這里的話,Processor對象就是一個策略;以上荔枝中有3個不同類型的策略應(yīng)用到對字符串的處理;
【9.4】java中的多重繼承
1)普通類的單繼承和接口的多繼承: 從 一個非接口類繼承,只能繼承一個類;其余的基類必須是接口;需要把所有的接口都放置在 implements 關(guān)鍵字之后,用逗號隔開它們;
2)可以繼承多個接口,并將其轉(zhuǎn)型為每個接口;
【荔枝】java多重繼承
interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } interface CanClimb { void climb(); }// 接口多重繼承 interface MyInterface extends CanFight, CanSwim, CanFly, CanClimb { }class ActionCharacter { public void fight() { } } // 【荔枝】 java多重繼承-普通類的單繼承和接口的多繼承 class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly {public void swim() { }public void fly() { } }public class Adventure {public static void t(CanFight x) { x.fight(); }public static void u(CanSwim x) { x.swim(); }public static void v(CanFly x) { x.fly(); }public static void w(ActionCharacter x) { x.fight(); }public static void main(String[] args) {Hero h = new Hero();t(h); // Treat it as a CanFightu(h); // Treat it as a CanSwimv(h); // Treat it as a CanFlyw(h); // Treat it as an ActionCharacter} } 分析)使用接口的核心原因:為了能夠向上轉(zhuǎn)型為多個基類型,由此帶來的靈活性;
分析)第二個原因:防止客戶端程序員創(chuàng)建該類的對象,并確保這僅僅是建立一個接口;
【問題】到底是使用接口還是抽象類??接口是首選;因為靈活;
【9.5】通過繼承來擴展接口
1)擴展接口: 新接口中添加新方法聲明;通過繼承在新接口中組合多個接口;
【荔枝】擴展接口
// 【荔枝】擴展接口 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 menace() {}public void destroy() {}public void kill() {}public void drinkBlood() {} }public class HorrorShow {static void u(Monster b) { b.menace(); }static void v(DangerousMonster d) {d.menace();d.destroy();}static void w(Lethal l) { l.kill(); }public static void main(String[] args) {DangerousMonster barney = new DragonZilla();u(barney);v(barney);Vampire vlad = new VeryBadVampire();u(vlad);v(vlad);w(vlad);} } 【9.5.1】組合接口時的名字沖突
1)當(dāng)繼承的父類和實現(xiàn)的接口的方法簽名或返回類型不同,會發(fā)生聲明呢??
補充)也有可能是:?兩個父接口的方法簽名或返回類型不同; 如? :
class A extends B implements C { } class B{void f1(); } class C {int f1(); } 【荔枝】組合接口時的名字沖突
(干貨——編碼注意事項,避免不同接口中使用相同的方法名)
// 【荔枝】組合接口時的名字沖突(已修正) 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 {@Overridepublic void f() { }@Overridepublic int f(int i) { return 1; } }class C3 extends C implements I2 {@Overridepublic int f(int i) { return 1; } }class C4 extends C implements I3 {@Overridepublic int f() { return 1; } } 注意:盡量避免不同接口中使用相同的方法名,以免造成可讀性混亂;
【9.6】適配接口
1)接口最吸引人的原因:允許同一個接口具有多個不同的具體實現(xiàn);接口的常見用法是策略設(shè)計模式;
2)如果創(chuàng)建一個新類,并讓 Scanner作用于它,讓該類去實現(xiàn) Readable 接口;
【荔枝】Readable接口的實現(xiàn)類,并讓Scanner作用于該類
// 荔枝-Readable接口的實現(xiàn)類,并讓Scanner作用于該類 public class RandomWords implements Readable {private static Random rand = new Random(47);private static final char[] capitals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();private static final char[] lowers = "abcdefghijklmnopqrstuvwxyz".toCharArray();private static final char[] vowels = "aeiou".toCharArray();private int count;public RandomWords(int count) {this.count = count;}@Overridepublic int read(CharBuffer cb) {if (count-- == 0)return -1;cb.append(capitals[rand.nextInt(capitals.length)]);for (int i = 0; i < 4; i++) {cb.append(vowels[rand.nextInt(vowels.length)]);cb.append(lowers[rand.nextInt(lowers.length)]);}cb.append(" ");return 10; }public static void main(String[] args) {Scanner s = new Scanner(new RandomWords(10));while (s.hasNext())System.out.println(s.next());} } /* Yazeruyac Fowenucor Goeazimom Raeuuacio Nuoadesiw Hageaikux Ruqicibui Numasetih Kuuuuozog Waqizeyoy */ // Readable 接口 public interface Readable {public int read(java.nio.CharBuffer cb) throws IOException; } 【荔枝】通過使用interface關(guān)鍵字提供的偽多重繼承機制,可以生成既是 RandomDoubles 又是 Readable的新類
// 荔枝-通過使用 interface關(guān)鍵字提供的偽多重繼承機制 // 可以生成既是 RandomDoubles 又是 Readable的新類 public class AdaptedRandomDoubles extends RandomDoubles implements Readable {private int count;public AdaptedRandomDoubles(int count) {this.count = count;}public int read(CharBuffer cb) {if (count-- == 0)return -1;String result = Double.toString(next()) + " ";cb.append(result);return result.length();}public static void main(String[] args) {Scanner s = new Scanner(new AdaptedRandomDoubles(7));while (s.hasNextDouble())System.out.println(s.nextDouble() + " ");} } /* 0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964 */ 【9.7】接口中的域
1)接口是一種便捷的用來創(chuàng)建常量組的工具:?因為接口中的任何域都自動是 public static final ;
【荔枝】接口是一種便捷的用來創(chuàng)建常量組的工具
// 荔枝-接口是一種便捷的用來創(chuàng)建常量組的工具 // 因為接口中的任何域都自動是 public static final public class Months {int JANUARY = 1, FEBRUARY = 2, MARCH = 3, APIRL = 4, MAY = 5, JUNE = 6, JULY = 7, AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10, NOVEMBER = 11, DECEMBER = 12; } 注意) java中標識具有常量初始化值的static final時,會使用大寫字母(用下劃線分隔多個單詞);不過java se5后,建議使用 enum 關(guān)鍵字來定義枚舉變量;
【9.7.1】初始化接口中的域
1)接口中的域不能是空final,但是可以被非常量表達式來初始化;
【荔枝】使用非常量表達式來初始化接口域
// 【荔枝】使用非常量表達式來初始化接口域 public interface RandVals {Random RAND = new Random(47);int RANDOM_INT = RAND.nextInt(10);long RANDOM_LONG = RAND.nextLong() * 10;float RANDOM_FLOAT = RAND.nextLong() * 10;double RANDOM_DOUBLE = RAND.nextDouble() * 10; } 2)這些static域會在類第一次加載時被初始化,荔枝如下:
// 荔枝-測試接口static域在類第一次加載時被初始化 public class TestRandVals {public static void main(String[] args) {print(RandVals.RANDOM_INT);print(RandVals.RANDOM_LONG);print(RandVals.RANDOM_FLOAT);print(RandVals.RANDOM_DOUBLE);} } /* 8 -32032247016559954 -8.5939291E18 5.779976127815049 */
【注意】這些域不是接口的一部分,其值存儲在接口的靜態(tài)存儲區(qū)域內(nèi); 即jvm內(nèi)存模型中的方法區(qū):線程公有,用于存儲編譯后的 類信息(Class類),常量,靜態(tài)變量 和 即時編譯后的數(shù)據(jù);
【9.8】嵌套接口(接口中再定義另一個接口)
1)接口嵌套荔枝:// 荔枝-接口嵌套荔枝 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 class CImp2 implements C {public void f() { }}private interface D {} // 普通類中嵌套一個接口(可以為private訪問權(quán)限) } interface E {interface G { void f(); } // 類中嵌套一個接口// Redundant "public": public interface H { void f(); } // 類中嵌套一個接口 void g();// Cannot be private within an interface: (注意:不可以為private訪問權(quán)限)// ! private interface I {} }public class NestingInterfaces {public class BImp implements A.B { // 普通類實現(xiàn)嵌套接口public void f() { }}class CImp implements A.C { // 普通類實現(xiàn)嵌套接口public void f() { }}class EImp implements E { public void g() { }}class EGImp implements E.G { // 普通類實現(xiàn)嵌套接口public void f() { }}class EImp2 implements E {public void g() {}class EG implements E.G { // 普通類實現(xiàn)嵌套接口public void f() {}}}public static void main(String[] args) {A a = new A();// Can't access A.D:// ! A.D ad = a.getD();// Doesn't return anything but A.D:// ! A.DImp2 di2 = a.getD();// Cannot access a member of the interface:// ! a.getD().f();// Only another A can do anything with getD():A a2 = new A();} } // /:~ 【注意】
注意1)嵌套接口可以擁有 public 和包可見性;
注意2)實體內(nèi)中可以嵌套private接口;而接口中不可以嵌套private接口;(干貨)
注意3)實現(xiàn)一個private接口:?那么它可以強制該接口中的方法定義不要添加任何類型信息,即無法向上轉(zhuǎn)型;
【9.9】接口與工廠
1)接口是實現(xiàn)多重繼承的途徑:?生成遵循某個接口的對象的典型方式是 工廠方法設(shè)計模式;(干貨——基于接口的工廠方法設(shè)計模式)
【荔枝】基于接口的工廠方法結(jié)構(gòu)
// 荔枝-基于接口的工廠方法結(jié)構(gòu) interface Service { void method1(); void method2(); } // 普通接口 interface ServiceFactory { Service getService(); } // 工廠接口class Implementation1 implements Service { // 實現(xiàn)普通接口的普通類Implementation1() {} public void method1() { print("Implementation1 method1"); }public void method2() { print("Implementation1 method2"); } }class Implementation1Factory implements ServiceFactory { // 實現(xiàn)工廠接口的工廠類public Service getService() { return new Implementation1(); } }class Implementation2 implements Service { // 實現(xiàn)普通接口的普通類Implementation2() {} public void method1() { print("Implementation2 method1"); }public void method2() { print("Implementation2 method2"); } }class Implementation2Factory implements ServiceFactory { // 實現(xiàn)工廠接口的工廠類public Service getService() { return new Implementation2(); } }public class Factories {public static void serviceConsumer(ServiceFactory fact) {Service s = fact.getService();s.method1();s.method2();}public static void main(String[] args) {// serviceConsumer(new Implementation1Factory()); serviceConsumer(new Implementation2Factory());} } /* Implementation1 method1 Implementation1 method2 Implementation2 method1 Implementation2 method2 */ 【荔枝】利用接口提高代碼復(fù)用率
// 【荔枝】利用接口提高代碼復(fù)用率 interface Game { // 普通接口boolean move(); }interface GameFactory { // 工廠接口Game getGame(); }class Checkers implements Game { // 實現(xiàn)普通接口的普通類private int moves = 0;private static final int MOVES = 3;public boolean move() {print("Checkers move " + moves);return ++moves != MOVES;} }class CheckersFactory implements GameFactory { // 實現(xiàn)工廠接口的工廠類public Game getGame() {return new Checkers();} }class Chess implements Game { // 實現(xiàn)普通接口的普通類private int moves = 0;private static final int MOVES = 4;public boolean move() {print("Chess move " + moves);return ++moves != MOVES;} }class ChessFactory implements GameFactory { // 實現(xiàn)工廠接口的工廠類public Game getGame() {return new Chess();} }// 工廠1 和 工廠2 復(fù)用代碼 public class Games {public static void playGame(GameFactory factory) {Game s = factory.getGame();while (s.move());}public static void main(String[] args) {playGame(new CheckersFactory()); // 工廠1playGame(new ChessFactory()); // 工廠2} } /* Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 */ 分析)如 Games 類表示一段復(fù)雜代碼,則這種方式允許你在不同類型的游戲中復(fù)用這段代碼;提高代碼復(fù)用率;
總結(jié)
以上是生活随笔為你收集整理的think-in-java(9)接口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备案查询网址(查备案网址)
- 下一篇: 硬盘与存储设备