9.1 抽象类和抽象方法
包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。
如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供方法定义。
创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样使用他们。抽象类还是很有用的重构工具,因为他们似的我们可以很容易地将公共方法沿着继承层次结构向上移动。
9.2 接口
Interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够向上转型为多种基类的类型,来实现某种类似多重继承变种的特性。
接口也可以包含域。但是这些域隐式地是static和final的。
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。接口可以在很大程度上放宽这种限制,因此,它使得我们可以编写可复用性更好的代码。
创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为“策略设计模式”
适配器模式实例:
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中的多重继承
可以继承任意多个接口,并可以向上转型为每个接口,因为每个接口都是一个独立类型。
如果知道某事物应该成为一个基类,那么第一选择应该是使它成为一个接口。
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 通过继承来扩展接口
一般情况下,只可以将extends用于单一类,但是可以引用多个基类接口。
打算组合的不同接口中使用相同的方法名通常会造成代码可读性的混乱,尽量避免这种情况。
9.6 适配接口
接口最吸引人的原因之一就是允许同一个接口具有多个不同的具体实现。在简单的情况下,它的体现通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取决于方法的使用者。
让方法接受接口类型,是一种让任何类都可以对该方法进行适配的方式。这就是使用接口而不是类的强大之处。
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());
}
} ///:~
接口也可以在嵌套接口中被实现为private,它可以强制该接口中的方法定义不要添加任何类型信息,也就是说,不允许向上转型。
在public方法中获取private接口对象,其返回值只能交给有权使用它的对象。
嵌套在另一个接口中的接口自动就是public的,而不能声明为private的。
private接口不能在定义它的类之外被实现。
9.9 接口与工厂
接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方法就是工厂方法设计模式。这与直接条用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。