9.1 抽象類和抽象方法
包含抽象方法的類叫做抽象類,如果一個類包含一個或多個抽象方法,該類必須被限定為抽象的。
如果從一個抽象類繼承,并想創(chuàng)建該新類的對象,那么就必須為基類中的所有抽象方法提供方法定義。
創(chuàng)建抽象類和抽象方法非常有用,因為他們可以使類的抽象性明確起來,并告訴用戶和編譯器打算怎樣使用他們。抽象類還是很有用的重構(gòu)工具,因為他們似的我們可以很容易地將公共方法沿著繼承層次結(jié)構(gòu)向上移動。
9.2 接口
Interface不僅僅是一個極度抽象的類,因為它允許人們通過創(chuàng)建一個能夠向上轉(zhuǎn)型為多種基類的類型,來實現(xiàn)某種類似多重繼承變種的特性。
接口也可以包含域。但是這些域隱式地是static和final的。
只要一個方法操作的是類而非接口,那么你就只能使用這個類及其子類。接口可以在很大程度上放寬這種限制,因此,它使得我們可以編寫可復(fù)用性更好的代碼。
創(chuàng)建一個能夠根據(jù)所傳遞的參數(shù)對象的不同而具有不同行為的方法,被稱為“策略設(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中的多重繼承
可以繼承任意多個接口,并可以向上轉(zhuǎn)型為每個接口,因為每個接口都是一個獨立類型。
如果知道某事物應(yīng)該成為一個基類,那么第一選擇應(yīng)該是使它成為一個接口。
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用于單一類,但是可以引用多個基類接口。
打算組合的不同接口中使用相同的方法名通常會造成代碼可讀性的混亂,盡量避免這種情況。
9.6 適配接口
接口最吸引人的原因之一就是允許同一個接口具有多個不同的具體實現(xiàn)。在簡單的情況下,它的體現(xiàn)通常是一個接受接口類型的方法,而該接口的實現(xiàn)和向該方法傳遞的對象則取決于方法的使用者。
讓方法接受接口類型,是一種讓任何類都可以對該方法進(jìn)行適配的方式。這就是使用接口而不是類的強大之處。
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());
}
} ///:~
接口也可以在嵌套接口中被實現(xiàn)為private,它可以強制該接口中的方法定義不要添加任何類型信息,也就是說,不允許向上轉(zhuǎn)型。
在public方法中獲取private接口對象,其返回值只能交給有權(quán)使用它的對象。
嵌套在另一個接口中的接口自動就是public的,而不能聲明為private的。
private接口不能在定義它的類之外被實現(xiàn)。
9.9 接口與工廠
接口是實現(xiàn)多重繼承的途徑,而生成遵循某個接口的對象的典型方法就是工廠方法設(shè)計模式。這與直接條用構(gòu)造器不同,我們在工廠對象上調(diào)用的是創(chuàng)建方法,而該工廠對象將生成接口的某個實現(xiàn)的對象。