Java编程思想---第九章 接口(下)

第九章 接口

9.5 通过继承来扩展接口

 

  通过继承可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口,这两种情况都可以获得新的接口:

package com.example.demo;

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 组合接口时的名字冲突

 

interface I1 { void f(); }
interface I2 { int f(int i); }
interface I3 { int f(); }

class C0 {
    public int f() { return 1; }
}

class C2 implements I1, I2 {
    public void f() {}
    public int f(int i) { return 1; }
}

class C3 extends C0 implements I2 {
    public int f(int i) { return 1; }
}

class C4 extends C0 implements I3 {
    public int f() { return 1; }
}

 

  这时困难来了,因为覆盖、实现和重载令人不快地搅在了一起,而且重载方法仅通过返回类型是区分不开的。

 

9.6 适配接口

 

  接口最吸引人的原因之一就是允许同一个接口具有多个不同的具体实现,在简单的情况中,它的体现形式通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取决于方法的使用者。因此,接口的一种常见用法就是前面提到的策略设计模式,此时编写一个执行某些操作的方法,而该方法将接受一个同样是你指定的接口。

 

9.7 接口中的域

 

  因为我们放入接口中的任何域都自动是staticfinal的,所以接口就成为了一种很便捷的用来创建常量组的工具,在Java SE5之前,这是产生与CC++中的enum具有相同效果的类型的唯一途径,因此在Java SE5之前的代码中你会看到下面这样的代码:

public interfaxe Months {
  int
    JANUARY = 1, FEBRUARY = 2, MARCH = 3,
    APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
    AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
    NOVEMBER = 11, DECEMBER = 12;
}

 

  有了Java SE5我们就可以使用更加强大的enum关键字,因此使用接口来群组常量已经显得没什么意义了。

 

9.7.1 初始化接口中的域

 

  在接口中定义的域不能是空final,但是可以被非常量表达式初始化,例如:

public interface RandVals {
  Random RAND = new Random(47);
  int RANDOM_INT = RAND.netInt(10);
  long RANDOM_LONG = RAND.nextLong() * 10;
  float RANDOM_FLOAT = RAND.nextLong() * 10;
  double RANDOM_DOUBLE = RAND.nextDouble() * 10;
}

 

  既然域是static的,它们就可以在类第一次被加载时初始化,这发生在任何域首次被访问时。

 

9.8 嵌套接口

 

package com.example.demo;

class A {
    interface B {
        void f();
    }
    public class BImp implements B {
        public void f() {}
    }
    public 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();
    }
    public interface H {
        void f();
    }
    void g();
}

public class NestingInterfaces {
    public class BImp implements A.B {
        public void f() {}
    }
    class CImp implements A.C {
        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();
        //! A.D ad = a.getD();
        //! A.DImp2 di2 = a.getD();
        //! a.getD().f();
        A a2 = new A();
        a2.receiveD(a.getD());
    }
}

 

  在类中嵌套接口的语法是显而易见的,就像非嵌套接口一样,可以拥有public和包方文权限两种可视性。

 

9.9 接口与工厂

 

  接口是实现多重继承的途径,而生产遵守某个接口的对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上通过这种方式我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现。

posted @ 2019-09-07 19:34  寓言i  阅读(179)  评论(0编辑  收藏  举报