9.1 抽象類和抽象方法
包含抽象方法的類叫做抽象類,如果一個(gè)類包含一個(gè)或多個(gè)抽象方法,該類必須被限定為抽象的入宦。
如果從一個(gè)抽象類繼承,并想創(chuàng)建該新類的對(duì)象室琢,那么就必須為基類中的所有抽象方法提供方法定義乾闰。
創(chuàng)建抽象類和抽象方法非常有用,因?yàn)樗麄兛梢允诡惖某橄笮悦鞔_起來研乒,并告訴用戶和編譯器打算怎樣使用他們汹忠。抽象類還是很有用的重構(gòu)工具淋硝,因?yàn)樗麄兯频奈覀兛梢院苋菀椎貙⒐卜椒ㄑ刂^承層次結(jié)構(gòu)向上移動(dòng)雹熬。
9.2 接口
Interface不僅僅是一個(gè)極度抽象的類,因?yàn)樗试S人們通過創(chuàng)建一個(gè)能夠向上轉(zhuǎn)型為多種基類的類型谣膳,來實(shí)現(xiàn)某種類似多重繼承變種的特性竿报。
接口也可以包含域。但是這些域隱式地是static和final的继谚。
只要一個(gè)方法操作的是類而非接口烈菌,那么你就只能使用這個(gè)類及其子類。接口可以在很大程度上放寬這種限制,因此芽世,它使得我們可以編寫可復(fù)用性更好的代碼挚赊。
創(chuàng)建一個(gè)能夠根據(jù)所傳遞的參數(shù)對(duì)象的不同而具有不同行為的方法,被稱為“策略設(shè)計(jì)模式”
適配器模式實(shí)例:
package chapter9;
/**
* Created by Blue on 2017/8/24.
* 9.3 適配器模式
*/
interface Processor1 {
String name();
Object process(Object input);
}
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;
}
}
class Apply1{
public static void process(Processor1 p, Object s) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s));
}
}
class FilterAdapter implements Processor1 {
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);
}
}
public class FilterProcessor {
public static void main(String[] args) {
Waveform w = new Waveform();
Apply1.process(new FilterAdapter(new LowPass(1.0)), w);
Apply1.process(new FilterAdapter(new HighPass(2.0)), w);
Apply1.process(new FilterAdapter(new BandPass(3.0, 4.0)),w);
}
}
9.4 java中的多重繼承
可以繼承任意多個(gè)接口济瓢,并可以向上轉(zhuǎn)型為每個(gè)接口荠割,因?yàn)槊總€(gè)接口都是一個(gè)獨(dú)立類型。
如果知道某事物應(yīng)該成為一個(gè)基類旺矾,那么第一選擇應(yīng)該是使它成為一個(gè)接口蔑鹦。
interface Fly {
void canFly();
}
interface Eat extends Fly {
void canEat();
}
interface Drink extends Fly {
void canDrink();
}
interface DoAll extends Fly, Eat, Drink {
void canDoAll();
}
class Animal {
public void canDoAll() {
}
}
class Bird extends Animal implements DoAll {
public void canFly() {
}
public void canEat() {
}
public void canDrink() {
}
}
9.5 通過繼承來擴(kuò)展接口
一般情況下,只可以將extends用于單一類箕宙,但是可以引用多個(gè)基類接口嚎朽。
打算組合的不同接口中使用相同的方法名通常會(huì)造成代碼可讀性的混亂,盡量避免這種情況柬帕。
9.6 適配接口
接口最吸引人的原因之一就是允許同一個(gè)接口具有多個(gè)不同的具體實(shí)現(xiàn)哟忍。在簡單的情況下,它的體現(xiàn)通常是一個(gè)接受接口類型的方法陷寝,而該接口的實(shí)現(xiàn)和向該方法傳遞的對(duì)象則取決于方法的使用者魁索。
讓方法接受接口類型,是一種讓任何類都可以對(duì)該方法進(jìn)行適配的方式盼铁。這就是使用接口而不是類的強(qiáng)大之處粗蔚。
9.7 接口中的域
接口中的任何域都是static和final的。
9.8 嵌套接口
//: interfaces/nesting/NestingInterfaces.java
package interfaces.nesting;
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 {
void f();
}
private class DImp implements D {
public void f() {}
}
public class DImp2 implements D {
public void f() {}
}
public D getD() { return new DImp2(); }
private D dRef;
public void receiveD(D d) {
dRef = d;
dRef.f();
}
}
interface E {
interface G {
void f();
}
// Redundant "public":
public interface H {
void f();
}
void g();
// Cannot be private within an interface:
//! private interface I {}
}
public class NestingInterfaces {
public class BImp implements A.B {
public void f() {}
}
class CImp implements A.C {
public void f() {}
}
// Cannot implement a private interface except
// within that interface's defining class:
//! class DImp implements A.D {
//! public void f() {}
//! }
class EImp implements E {
public void g() {}
}
class EGImp implements E.G {
public void f() {}
}
class EImp2 implements E {
public void g() {}
class EG implements E.G {
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();
a2.receiveD(a.getD());
}
} ///:~
接口也可以在嵌套接口中被實(shí)現(xiàn)為private饶火,它可以強(qiáng)制該接口中的方法定義不要添加任何類型信息鹏控,也就是說,不允許向上轉(zhuǎn)型肤寝。
在public方法中獲取private接口對(duì)象当辐,其返回值只能交給有權(quán)使用它的對(duì)象。
嵌套在另一個(gè)接口中的接口自動(dòng)就是public的鲤看,而不能聲明為private的缘揪。
private接口不能在定義它的類之外被實(shí)現(xiàn)。
9.9 接口與工廠
接口是實(shí)現(xiàn)多重繼承的途徑义桂,而生成遵循某個(gè)接口的對(duì)象的典型方法就是工廠方法設(shè)計(jì)模式找筝。這與直接條用構(gòu)造器不同,我們?cè)诠S對(duì)象上調(diào)用的是創(chuàng)建方法慷吊,而該工廠對(duì)象將生成接口的某個(gè)實(shí)現(xiàn)的對(duì)象袖裕。