接口

  1. 接口的概念
    接口表示某种能力,是若干行为的集合。
    接口可以被看作为某种数据引用类型,接口是比抽象类更抽象的“类型”。
    接口描述着具备某种能力所应该包含的行为集合,它只提供抽象层面的概念。具体的实现是由接口的实现类(可以看作是接口的子类)来完成的。
    这样可以将行为的定义与实现分离开,对程序的代码结构进行优化。
    一切对象都具备着各种能力,即从一切对象中都可以抽象出不同的接口

  2. 接口的声明
    接口的声明使用interface关键字。接口代码也是被保存在java的源代码文件中的,编译生成的字节码文件同样是.class后缀。

public interface Moveable{
       void move();
}

各版本JDK对接口的定义有些不同:
相同点:
接口中所有的变量都公有的静态常量(public static final修饰)
接口中所有非static方法都是公有的。
不同点:
Java 7及以前版本:接口中只能包含公有的抽象方法,不能出现有实现体的具体方法
Java 8:接口中可以包含还有实现的具体方法,这种方法分为两类:默认方法(default)、静态方法(static),但它们必须是公有的
Java 9至当前版本:接口中可以加入私有的静态方法和私有的strictfp方法

  1. 实现接口
    类与接口之间的关系被称为实现,即类能实现某些接口。
    实现关系的声明用implements关键字
    当类实现接口以后,相当于声明此类具备了已经实现接口中定义的能力,实现类需要重写接口中的所有抽象方法,除非此类是抽象类。
public class Car implements Moveable{
       private int currentSpeed;
       //构造器
       public Car(int currentSpeed) {
        super();
        this.currentSpeed = currentSpeed;
        }
        // 汽车类的对象实现了Moveable接口中定义的抽象方法
        // 表示汽车拥有可移的能力,具体行为由以下方法实现
        @Override
        public void move(){
              System.out.println(String.format("汽车在公路上以%d的时速行驶着。", currentSpeed));
        }
          
}

实现类会继承接口中的所有公有方法。

  1. 类实现接口的意义

    • 类实现接口,即把接口的类型赋予实现类,实现类就具备了接口定义的能力。
    • 在实现类中重写接口里的方法,即让接口中定义的抽象行为具体化。
    • 接口与实现类,分离了代码中的高层功能契约与具体行为实现,可以让优化程序代码结构的工作更加轻松。
  2. 类可以实现多个接口

    • Java的类是单继承体系,即一个类的直接父类只能有一个。虽然此特性避免了多继承体系带来的混乱,但同时也让Java类的继承成本大大提高。
    • 接口可以弥补单继承体系的缺点,因为Java的类可以同时实现多个接口,也就是说实现了多个接口的类同样也拥有多种类型(多种功能)。即Java使用多接口实现替代了类的多重继承,保留了多重继承的优点,避免了它带来的问题。
    • 多继承的弊端:当多个父类中有相同行为时,子类调用会产生不确定性
    • 其根本原因在于多继承父类中的方法是有具体实现的,而导致调用运行时,不确定运行哪个父类中的方法。而接口中的行为往往都是抽象方法,这些方法由子类具体实现,所以避免了以上问题。
      多接口实现的例程:
public interface Moveable {
    void move();
}
public interface Flyable {
    void fly();
}
public class Plane implements Moveable, Flyable {
    private String name;
    public Plane(String name) {
        super();
        this.name = name;
    }
    @Override
    public void fly() {
        System.out.println(String.format("%s正在天空中飞行。", name));
    }
    @Override
    public void move() {
        System.out.println(String.format("%s正在航空跑道上加速,准备起飞。", name));
    }
}
  1. 接口的继承
    接口之间也有继承关系,同样使用extends关键字声明,但与类不同的是,一个接口可以同时继承自多个父接口,即在Java中,接口是多重继承的。
    接口的多重继承例程:
// SuperHero接口中拥有3个方法:
// 从两个父类继承来的fly()和move()
// 自己扩展出的swim()
public interface SuperHero extends Flyable, Moveable {
    void swim();
}

public class MonkyKing implements SuperHero {
    @Override
    public void fly() {

    }

    @Override
    public void move() {

    }

    @Override
    public void swim() {

    }
}

如果在多个父接口中存在着相同方法,实现类只需要实现此方法一次即可

  1. 继承父类的同时实现接口
    如果一个类已经扩展自一个父类,又想对其进行功能扩展,就可以让此类去实现相应的功能接口。

父类提供基础属性和行为,接口提供扩展功能

接口的优点

  • 接口为类提供了功能的扩展点
  • 接口公开了通用的行为契约或规范,而具体的实现被隐藏到实现类中
  • 接口降低了程序代码的耦合度,让程序的扩展和优化更加轻松灵活

接口与抽象类的异同(java 12)
相同点:
a. 都可以创建程序的抽象层次结构
b. 都不可以被直接实例化
c. 通常都声明抽象方法来定义行为能力,让子类去扩展这些功能

不同点:
a. 抽象类中可以声明构造方法,接口中不能存在构造方法
b. 子类只能继承一个抽象类,但可以实现多个接口、
c. 类之间是单继承,接口之间是多继承
d. 抽象类为子类提供基础数据和方法,它们之间是is-a关系;接口为实现类提供扩展功能,它们之间是like-a关系
e. java 7及以前的版本,抽象类中可以声明程序访问修饰符修饰的抽象和具体方法,而接口中只有声明公有的抽象方法
f. java 8版本时,接口中可以定义具有方法体的默认方法和静态方法,但它们一定是公有的
g. 虽然是不推荐的做法,但在抽象类中的静态方法是可以通过引用变量名进行调用的;而接口中的静态方法必须使用接口名称调用
h. java 9以后,接口中的静态方法可以被声明为私有的,但不可以是protected和package级别的
i. java 9以后,接口中可以加入私有的被strictfp关键字修饰的具体方法,此类方法可以是静态的,也可以是非静态的,但除了private以外不能使用其他访问修饰符修饰。

  1. 如何在接口和抽象类中进行选择

    • 优先使用接口
    • 当子类中存在共同行为和属性时,才让子类继承抽象类
  2. 接口中的默认方法
    java 8以后,在java中可以添加以default关键字修饰的方法,这种方法被称为默认方法。默认方法是有具体实现的方法。
    添加默认方法的主要目的:
    在软件的长期维护过程中,如果向既有接口里添加新的抽象方法,会导致要在所有此接口的实现类中都去重写新加入的方法,对代码有巨大影响。
    而引入具有实现的默认方法就解决了以上问题。默认方法中有着相对通用的默认实现,如果实现类需要重写此方法,再去进行子类中的重写。默认方法以一种相对平缓的方式扩展接口的行为,不是强制让实现类重写新方法,而是引导实现类去重写新方法。

默认方法可以被认为是Lambda表达式和JDK标准API之间的桥梁。

你可能感兴趣的:(接口)