接口

一、接口的语法

语法:

public interface 接口名{

  1. // 属性(所有的属性均为静态常量)
  2. // 方法(所有的方法均为抽象方法)

}

注意:接口没有构造方法,也不能创建对象。

public interface MyInterface {
    int COUNT = 10; // 属性默认是public static final
    void m1(); // 方法默认是public abstract
}

二、与抽象类的异同

经典面试题:

相同点:

  • 都不能直接创建对象
  • 都可以定义抽象方法

不同点:

  • 抽象类可以定义构造方法、代码块,而接口不能定义
  • 抽象类可以定义实例属性,静态属性,实例方法,静态方法;而接口只能定义静态常量,抽象方法、jdk8后可以定义静态方法。

三、接口的概念

是一种能力和约定,接口代表能力,方法代表约定。

主要是为了解决Java中多继承的问题,而又不会出现c++中多继承相关的问题。因为接口中的方法没有实现,即使从多个接口继承过来相同的方法也不会产生任何问题。

四、基本使用

public interface USB {
    void use();
}

public class Fan implements USB{
    @Override
    public void use() {
        System.out.println("usb风扇被使用");
    }
}

public class KeyBoard implements USB{
    @Override
    public void use() {
        System.out.println("usb键盘被使用");
    }
}

public class TestMain {
    public static void main(String[] args) {
        USB u1 = new Fan();
        u1.use();
        USB u2 = new KeyBoard();
        u2.use();
    }
}

五、接口的多态

接口的使用场景:需要具备某种能力,但是又没有相应的父子关系存在时,就应该使用接口。

例如:

  • 电脑上有USB接口,只要具备有使用USB能力的设备都可以连接,USB风扇、键盘、鼠标、手机等,它们很难找到父子关系,从而抽象出父类,此时应该使用接口。

  • 要举办一次飞行表演,可以使用鸽子、飞机、气球、天使等来进行飞行表演,此时也无法找到或者抽象出相应的父类,应该使用接口,只要具备有飞行能力即可。

// USB接口的案例
public interface USB {
    void use();
}

public class Fan implements USB{
    @Override
    public void use() {
        System.out.println("usb风扇被使用");
    }
}

public class KeyBoard implements USB{
    @Override
    public void use() {
        System.out.println("usb键盘被使用");
    }
}

public class Computer {
    public void operate(USB usb) {
        System.out.println("正在使用电脑上的usb接口");
        usb.use();
    }
}

public class TestMain {
    public static void main(String[] args) {
        USB u1 = new Fan();
        USB u2 = new KeyBoard();
        Computer computer = new Computer();
        computer.operate(u2);
    }
}
// 飞行表演的案例
// 涉及到的接口为飞行接口(Flyable、fly())、鸽子(Bird)、飞机(Plane)、天使(Angel)
// 应用场景的类:节日(Day、表演show(飞行接口))
/**
 * 飞行能力
 */
public interface Flyable {
    void fly();
}
public class Bird implements Flyable{
    @Override
    public void fly() {
        System.out.println("鸽子正在飞行表演...");
    }
}
public class Angel implements Flyable {
    @Override
    public void fly() {
        System.out.println("天使正在进行飞行表演...");
    }
}
public class Plane implements Flyable {
    @Override
    public void fly() {
        System.out.println("飞机正在进行飞行表演...");
    }
}
/**
 * 节日
 */
public class Day {
    /**
     * 表演
     */
    public void show(Flyable flyable) {
        System.out.println("表演开始。。。");
        flyable.fly();
    }
}
public class TestMain {
    public static void main(String[] args) {
        Day day = new Day();
        Flyable flyable = new Angel();
        day.show(flyable);
    }
}

六、同时继承类并实现接口

/**
 * 动物类作为父类
 */
public abstract class Animal {
    public abstract void eat();
}

public interface Swimmable {
    void swim();
}

public interface Runnable {
    void run();
}

// 同时实现多个接口,使用逗号隔开
// 继承类同时又实现接口,需要将继承放到前面
public class Dog extends Animal implements Runnable, Swimmable{
    @Override
    public void eat() {
        System.out.println("狗正在吃骨头...");
    }

    @Override
    public void swim() {
        System.out.println("狗正在游泳");
    }

    @Override
    public void run() {
        System.out.println("狗正在跑...");
    }
}

public class TestMain {
    public static void main(String[] args) {
        // 当创建子类对象时,可以调用该类中所有的方法(继承自父类或实现接口)
        Dog dog = new Dog();
        dog.eat();
        dog.run();
        dog.swim();
        // 当使用父类引用指向子类对象时,只能调用父类的方法,要调用其他的方法,需要向下转型
        Animal animal = new Dog();
        animal.eat();
        // 当使用接口来引用实现类的对象时,也只能调用该接口中声明的方法,要调用其他的方法,需要向下转型
        Runnable runnable = new Dog();
        runnable.run();
        Swimmable swimmable = new Dog();
        swimmable.swim();
    }
}

七、常见关系

类与类:

  • 单继承,使用extends关键字

类与接口:

  • 多实现,implements 接口1, 接口2, 接口3

接口与接口:

  • 多继承,extends 接口1, 接口2
public interface A {
    void a();
}

public interface B {
    void b();
}

public interface C extends A, B{
    void c();
}

public class MyClass implements C{
    @Override
    public void a() {
    }

    @Override
    public void b() {
    }

    @Override
    public void c() {
    }
}

八、常量接口

一种特殊的接口,在里面定义项目中需要的常量,不定义任何方法。

因为在接口中定义的变量默认是常量,比类更适合于定义常量。

public interface Constants {
    int PAGE_SIZE = 10;
    String MESSAGE_TYPE = "1";
}

九、默认方法和静态方法(了解)

在jdk8的新版本中,添加了默认方法和静态方法。

静态方法需要类名调用,但是默认方法,需要创建实现类的对象才能调用。

注意:

  • 如果一个类实现了多个接口,在多个接口中都有相同的静态属性或静态方法,不会报错,在使用时应该使用接口名去调用相应的静态属性或静态方法。
  • 如果一个类实现了多个接口,在多个接口中有相同默认方法,会报错,要求必须在实现类中重写该方法。如果在重写时,需要调用父接口中的默认方法,需要使用接口名.super.方法的方式。
public interface A {
    int COUNT = 5;

    public static void m2() {
        System.out.println("A接口中的静态m2方法");
    }

    default void m1() {
        System.out.println("A接口中的m1方法");
    }
}

public interface B {
    int COUNT = 10;

    default void m1() {
        System.out.println("B接口中的m1方法");
    }

    public static void m2() {
        System.out.println("B接口中的静态m2方法");
    }
}

public class AClass implements A, B{
    @Override
    public void m1() {
        A.super.m1(); // 调用A作为父接口中的m1方法
        B.super.m1();
        System.out.println("AClass中的m1方法");
    }
}

public class TestMain {
    public static void main(String[] args) {
        A a = new AClass();
        a.m1();
        // 使用接口名去调用相应的静态属性或静态方法
        A.m2();
        B.m2();
        System.out.println(A.COUNT);
        System.out.println(B.COUNT);
    }
}

十、接口回调

回调字面意思是回头调用。

例如:

老师布置作业。

学生完成作业。

学生提交作业。

老师批改作业。

public interface Callback {
    void pigai();
}

public class Teacher implements Callback{
    private Student student;

    public Teacher(Student student) {
        super();
        this.student = student;
    }

    public void buzhi() {
        System.out.println("老师布置作业");
        student.wancheng(this);
    }

    @Override
    public void pigai() {
        System.out.println("老师批改作业");
    }
}

public class Student {
    public void wancheng(Callback callback) {
        System.out.println("学生完成作业...");
        System.out.println("学生提交作业...");
        callback.pigai();
    }
}

public class TestMain {
    public static void main(String[] args) {
        Student student = new Student();
        Teacher teacher = new Teacher(student);
        teacher.buzhi();
    }
}

可以再创建一个家长也参与布置作业和批改作业。

public class Parent implements Callback{
    private Student student;

    public Parent(Student student) {
        super();
        this.student = student;
    }

    public void buzhi() {
        System.out.println("家长布置作业");
        student.wancheng(this);
    }

    @Override
    public void pigai() {
        System.out.println("家长批改作业");
    }
}
public class TestMain {
    public static void main(String[] args) {
        Student student = new Student();
        Parent parent = new Parent(student);
        parent.buzhi();
    }
}