9.接口

62 阅读5分钟

第9章 接口

接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。

9.1 抽象类和抽象方法

几点概念:

  • 通用接口建立起一种基本形式,表示所有导出类的共同部分;
  • 用abstract关键字修饰的方法是抽象方法;
  • 抽象方法仅有声明没有方法体;
  • 含有抽象方法的类必须是抽象类;
  • 抽象类中可以没有抽象方法;
  • 抽象类中可以有非抽象方法。
  • 继承抽象类必须实现抽象方法,或者使导出类也是抽象的。
public abstract class Instrument {
    public abstract void play();
    public void what(){
        System.out.println("Instrument");
    }
}

public class Brass extends Instrument {
    @Override
    public void play() {
        System.out.println("Brass play");
    }

    @Override
    public void what() {
        System.out.println("Brass");
    }
}

public class Wind extends Instrument {
    @Override
    public void play() {
        System.out.println("Wind play");
    }

    @Override
    public void what() {
        System.out.println("wind");
    }
}

public class Music {
    public void tunneAll(Instrument[] instruments){
        for (Instrument instrument : instruments) {
            instrument.what();
            instrument.play();
        }
    }
}

 @Test
    public void test2(){
        Instrument[] instruments = {new Brass(),new Wind()};
        Music music = new Music();
        music.tunneAll(instruments);
    }
/*
Brass
Brass play
wind
Wind play
*/

9.2 接口

interface关键字使抽象的概念更向前了一步,只做了声明,没有提供任何的实现,表示“所有实现了该接口的类看起来都像这样”。

接口中的域默认是public static final的,方法默认是public的。

public interface Instrument {
     int a =1;
    void play();

    void what();
}

public class Brass implements Instrument {
    @Override
    public void play() {
        System.out.println("Brass play");
    }

    @Override
    public void what() {
        System.out.println("Brass");
    }
}

9.3 完全解耦

// 空中行为接口
public interface SkyAction {
    void flay();
}

// 定义飞行动物抽象类,该类实现了空中行为接口
public abstract class FlyAnimal implements SkyAction{
}

// 定义鸟类
public class Bird extends FlyAnimal {
    @Override
    public void flay() {
        System.out.println("鸟飞行");
    }
}

// 定义鹰类
public class Eagle extends FlyAnimal {
    @Override
    public void flay() {
        System.out.println("鹰飞行");
    }
}

// 定义飞行器抽象类(假设该类在定义SkyAction接口前就已存在,或者该类是依赖的jar包中的类,总之,无法修改)
public abstract class Aerobat {
    public abstract void flay();
}

// 定义飞机类
public class Plane extends Aerobat {
    @Override
    public void flay() {
        System.out.println("飞机飞行");
    }
}

// 适配器模式:为了使用特定接口,定义适配器
public class AerobatAdapter implements SkyAction {
    private Aerobat aerobat;
    public AerobatAdapter(Aerobat a){
        aerobat = a;
    }
    @Override
    public void flay() {
        aerobat.flay();
    }
}

// 应用类,
public class Apply {
    // 策略模式:根据传递对象参数的不同产生不同的行为
    // 个人理解是,不同的行为本质上是定义在响应的类中,而此类通过传入的参数对象,调用了相应的方法。
    public void action(SkyAction action){
        action.flay();
    }
}

// 测试
  @Test
    public void test3(){
        Apply apply = new Apply();
        apply.action(new Bird());
        apply.action(new Eagle());
        apply.action(new AerobatAdapter(new Plane()));
    }
/*
鸟飞行
鹰飞行
飞机飞行
*/

就以上功能而言,使用继承也是能实现的。java中用实现接口表达拥有某种功能,用继承表现is-a的关系,显然飞行动物不是空中行为,飞行器也不能继承飞行动物,用实现接口更能很好的表达。

从另一种角度来说,继承关系中,子类在初始化时会初始化基类,降低性能,而接口不存在这个问题。

另外,由于java中的单继承限制,假如现在要创建A类,它需要同时实现B类和C类中的功能,但是B类和C类都是相互独立的,此时通过继承就无法实现了。

9.4 Java中的多重继承

public class Animal {
    
    public void fly(){
        System.out.println("飞翔");
    }
}

public interface CanFly {
    void fly();
}

public interface CanSwim {
    void swim();
}

public class Bird extends Animal implements CanFly,CanSwim {
    @Override
    public void swim() {
        System.out.println("游泳");
    }
}

public class Test {
    public static void t(Animal a){
        a.fly();
    }
    public static void f(CanFly fly){
        fly.fly();
    }
    public static void d(CanSwim s){
        s.swim();
    }

    public static void main(String[] args) {
        Bird bird = new Bird();
        t(bird);
        f(bird);
        d(bird);
    }
}
/*
注意,Bird中并没有直接提供对fly()方法的实现,但是基类提供了同名方法,该默认方法被认为实现了接口中的方法。
*/

9.5 通过继承来扩展接口

  • 接口中允许多继承;
  • 准备用来组合的接口中不要含有相同名字的方法。

9.6 适配接口

常用的两种设计方式是策略模式和适配器模式。

public class RandomWord implements Readable {
    private int i ;
    RandomWord(int i){
        this.i = i;
    }
    @Override
    public int read(CharBuffer cb) {
        if (i-- == 0){
            return -1;
        }
        cb.append('a');
        return 1;
    }
}

public class Test {
    public static void main(String[] args) {
        // 定义统一的接口,传入不同的实现类,产生不同的结果
       Scanner scanner = new Scanner(new RandomWord(10));
       while (scanner.hasNext()){
           System.out.println(scanner.next());
       }
    }
}

public class RandomDouble {

    public double f(){
        return Math.random()*10;
    }
}

// 为了使用特定的接口,可以使用适配器模式
public class RandomDoubleAdapter extends RandomDouble implements Readable {
    public int i;
    public RandomDoubleAdapter(int i){
        this.i = i;
    }
    @Override
    public int read(CharBuffer cb) throws IOException {
        if (i--==0){
            return -1;
        }
        cb.append((char) f());
        return 0;
    }
}

public class Test {
    public static void main(String[] args) {
       Scanner scanner = new Scanner(new RandomDoubleAdapter(10));
       while (scanner.hasNext()){
           System.out.println(scanner.next());
       }
    }
}

9.7 接口中的域

public interface One {
    // 默认是public static final的
    // 必须进行显示初始化
     String NAME ="ding";
     // 支持方法赋值
     int AGE = Bird.getAge();
}

9.8 嵌套接口

类中嵌套接口

public class A {
    /**
     * 包访问权限
     */
    interface B{
        void f();
    }
    public class BImp1 implements B{
        @Override
        public void f() {

        }
    }
    
    private class BImp2 implements B{
        @Override
        public void f() {

        }
    }

    public interface C{
        void f();
    }

    class CImp1 implements C{
        @Override
        public void f() {

        }
    }

    private class CImp2 implements C{
        @Override
        public void f() {

        }
    }

    /**
     * 私有接口
     * 重点注意
     */
    private interface D{
        void f();
    }

    public class DImp1 implements D{
        @Override
        public void f() {

        }
    }

    private class DImp2 implements D{
        @Override
        public void f() {

        }
    }

    /**
     * 返回一个私有的接口实现类
     * @return
     */
    public D getD(){
        return new DImp1();
    }

    /**
     * 接收一个接口实现类
     * @param d
     */
    public void receiveD(D d){
        d.f();
    }
}
// 其他类可以实现A中的非private接口
public class ImplAInterfece implements A.C{
    @Override
    public void f() {
        
    }
    
    class Impl implements A.B{
        @Override
        public void f() {
            
        }
    }
}

public class Test {
    public static void main(String[] args) {
        A a = new A();
        // A.D是私有的,不用在这使用
        // A.D d = a.getD();
        // A.DImp1不能接收一个接口
        //A.DImp1 di1 =a.getD();
        // 不能在这使用一个私有的接口对象
        //a.getD().f();
        // 只有A对象的方法是可以使用的
        a.receiveD(a.getD());
    }
}

接口中嵌套接口

public interface E {

    void f();
    interface G{
        void f();
    }

    // 接口中不能嵌套私用接口,这是接口中不允许有私有成员特性决定的
    //private interface H{}
}
// 实现接口时不需要实现内部的接口
public class EImpl implements E {
    @Override
    public void f() {

    }
}

class HImpl implements E.G{
    @Override
    public void f() {

    }
}

9.9 接口与工厂

public interface Game {
    boolean move();
}
public class Agame implements Game {
    private static final int moves = 3;
    private int step =0;
    @Override
    public boolean move() {
        System.out.println("A移动了");
        return ++step != moves;
    }
}
public class Bgame implements Game {
    private static final int moves = 4;
    private int step =0;
    @Override
    public boolean move() {
        System.out.println("B移动了");
        return ++step != moves;
    }
}

public interface GameFactory {
    Game getGame();
}
public class AgameFactory implements GameFactory {
    @Override
    public Game getGame() {
        return new Agame();
    }
}
public class BgameFactory implements GameFactory {
    @Override
    public Game getGame() {
        return new Bgame();
    }
}

public class Test {

    public static void playGame(GameFactory gameFactory){
        Game game = gameFactory.getGame();
       while (game.move()){}
    }

    public static void main(String[] args) {
        /*
        工厂模式将创建对象的任务交给工厂,将实现与接口完全分离,实现了解耦操作
        在本例中则体现的是复用playGame()的代码
         */
        playGame(new AgameFactory());
        playGame(new BgameFactory());
    }
}