29、Java 中的接口详解

简介: 29、Java 中的接口详解

一、接口介绍

(1) 生活中的 “接口”

📱 苹果手机的充电插口和安卓手机📲的充电插口是不一样的。例如:充电器有两个厂商生成(分别是:喜羊羊🐑厂商和老鼠厂商🐭),喜羊羊厂商和老鼠厂商各自制定了它们自己的充电器的大小和形状标准(是方形还是圆形)。苹果🍎手机商家觉得老鼠厂商的(圆形)充电器比较好,所以苹果厂商按照老鼠厂商的充电器的规范制作了苹果手机的充电插口。安卓手机的商家则觉得喜羊羊厂商的充电器比较酷,所以安卓手机的商家按照喜羊羊厂商的充电器规范制作安卓手机的充电器插口。

☘️ 充电器的大小与形状就是一个规范,一个标准;手机若想使用该种类型的充电器充电,就必须按照该充电器的规范设计手机的充电插口。


🏘️ 在生活中,接口二字应该最常使用在 USB 接口上。

Universal Serial Bus(通用串行总线)是一个外部总线标准,用于规范电脑与外部设备的连接和通讯;是应用在 PC 领域的接口技术。

🏘️ 电脑和外部设备的连接和通讯通过 USB 接口实现,USB 接口的大小和传输速率由 USB 厂商规定好(类似制定一个规范和标准),电脑若想通过 USB 连接外部设备,电脑就要按照 USB 厂商制定的 USB 的制作规范(标准) 来制作自己的 USB 插槽。【电脑生成商实现了 USB 接口的规范】


(2) 官方教程介绍

✏️ There are a number of situations in software engineering when it is important for disparate groups of programmers to agree to a contract(协议) that spells out(详细说明) how their software interacts. Each group should be able to write their code without any knowledge of how the other group’s code is written. Generally speaking, interfaces are such contracts.

📜 在软件工程中,来自不同小组的程序设计者共同同意一份协议来详细阐明它们的软件如何进行交互是很重要的。

📜 每个组的程序设计者能够编写自己的代码,无需关心其他组的程序设计者的代码是如何编写的。一般来说:接口就是这样的一个协议(契约)


✏️ For example, imagine a futuristic(未来的) society where computer-controlled robotic cars transport(运送) passengers through city streets without a human operator.

✏️ Automobile manufacturers(汽车制造商) write software (Java, of course) that operates the automobile—stop, start, accelerate, turn left, and so forth.

✏️ Another industrial group, electronic guidance instrument manufacturers, make computer systems that receive GPS (Global Positioning System) position data and wireless transmission of traffic conditions and use that information to drive the car.

📜 想象一下,未来社会,计算机在没有人操控的情况下控制智能汽车运送乘客穿越城市的大街小巷。汽车制造商用 Java 语言编写软件来控制汽车的启动、停止、加速和转弯等。另一个工业集团,电子导航仪器制造商制作计算机系统,用于接收 GPS(全球定位系统)位置数据和交通状况的无线传输,并使用这些信息来驾驶汽车。


✏️ The auto manufacturers must publish an industry-standard interface that spells out in detail what methods can be invoked to make the car move (any car, from any manufacturer). The guidance manufacturers can then write software that invokes the methods described in the interface to command the car. Neither industrial group needs to know how the other group’s software is implemented(实现). In fact, each group considers its software highly proprietary(专有性) and reserves the right to modify it at any time, as long as it continues to adhere to the published interface.

📜 汽车制造商必须发布一个行业标准接口,详细说明可以调用哪些方法来使汽车移动(任何汽车,来自任何制造商)。

📜 导航制造商可以编写软件来调用接口中的方法去控制汽车。

📜 两个工业集团都不需要知道其他集团的软件是如何实现的(如何实现使汽车启用)。事实上,每个团体都认为其软件具有高度专有性,并保留随时对其进行修改的权利,只要它继续遵守已发布的 协议(标准) 即可。


✏️ In the Java programming language, an interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods. Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces.

📜 在 Java 语言中,接口和类一样是引用类型

📜 接口中只能包含:① 常量;② 方法签名;③ 默认方法;④ 静态方法;⑤ 嵌套类型

📜 在接口中,方法体只存在于默认方法和静态方法中

📜 接口不能被实例化

📜 接口只能被类实现(implements)或被其他接口继承


✏️ Note that the method signatures have no braces and are terminated with a semicolon.

📜 方法签名没有花括号,并由分号结尾

(3) 接口介绍

🌼 接口中定义一些抽象方法(没有具体实现),类可实现(implements)接口中的方法,给予接口中的抽象方法具体的实现

汽车接口:

/**
 * 汽车接口
 */
public interface ICar {
    int DEFAULT_SPEED = 30;
    Direction left = new Direction("左");
    Direction right = new Direction("右");
    void start();
    void stop();
    void accelerate(int speed);
    default void speak() {
        System.out.println("ICar_defaultMethod_speak()");
    }
    static void eat() {
        System.out.println("ICar_staticMethod_eat()");
    }
    class Direction {
        String name;
        Direction(String name) {
            this.name = name;
        }
    }
}

实现类:

/**
 * AutoControlCar 类实现(implements)ICar 接口
 * AutoControlCar 类给予 ICar 接口中的抽象方法具体实现
 */
public class AutoControlCar implements ICar {
    @Override
    public void start() {
        System.out.println("AutoControlCar - start()");
    }
    @Override
    public void stop() {
        System.out.println("AutoControlCar - stop()");
    }
    @Override
    public void accelerate(int speed) {
        System.out.println("AutoControlCar - accelerate()");
    }
}

🌼 jdk7 之前,接口中的全部方法都没有方法体

🌼 jdk8 之后,接口中可以有静态方法,默认方法(也就是接口中的方法可以有具体实现)

(4) 请家教

Interfaces are such contracts. 接口是一种协议

一个家长💁‍♀️ 要请家教👨‍🏫教 TA 的孩子学习,TA 对家教的要求如下:① 擅长英语;② 擅长数学;③ 擅长画画。

📖 接口是一种协议

📖 接口是一个标准

📖 接口是一个规范

要成为家教老师👨‍🏫只需满足协议中的内容即可

要成为家教老师👨‍🏫只需实现接口中的抽象方法即可

家长制定家教老师👩‍🏫的规范(接口),想要成为家教老师的人只需实现该规范(接口中的方法)即可

📖 接口是一种规范,某个类实现了该接口,则表明该类能够做某事…

📖 上图:老师👨‍🏫实现了家教协议,表明老师可以当家教老师

机器人实现了家教协议,表明机器人可以当家教老师

狗🐶实现了家教协议,表明狗可以当家教老师

家教协议【接口】

/**
 * 家教协议, 家教接口
 */
public interface ITutor {
    void english();
    void math();
    void paint();
}

实现(implements)了 ITutor 接口的类有当家教的能力

/**
 * Teacher 实现了 ITutor
 * Teacher 有当家教的能力
 */
public class Teacher implements ITutor {
    @Override
    public void english() {
        System.out.println("Teachers teach English.");
    }
    @Override
    public void math() {
        System.out.println("Teachers teach math.");
    }
    @Override
    public void paint() {
        System.out.println("Teachers teach painting.");
    }
}
/**
 * Robot 实现了 ITutor
 * Robot 有当家教的能力
 */
public class Robot implements ITutor {
    @Override
    public void english() {
        System.out.println("Robots teach English.");
    }
    @Override
    public void math() {
        System.out.println("Robots teach math.");
    }
    @Override
    public void paint() {
        System.out.println("Robots teach painting.");
    }
}
/**
 * Dog 实现了 ITutor
 * Dog 有当家教的能力
 */
public class Dog implements ITutor {
    @Override
    public void english() {
        System.out.println("Dogs teach English.");
    }
    @Override
    public void math() {
        System.out.println("Dogs teach math.");
    }
    @Override
    public void paint() {
        System.out.println("Dogs teach painting.");
    }
}

接口是一种协议。接口的功能异常强大,博主有一点点开发经验,所以能够感受得到。

二、接口细节

✏️ 接口不能被实例化

✏️ 接口中的成员默认都是public(无需手动写 public

✏️ 接口中的方法默认都是抽象方法(无需手动写 abstract

✏️ 非抽象类实现(implements)接口,则必须实现接口中的所有抽象方法(给予接口中的所有抽象方法以具体实现

✏️ 抽象类实现接口,不用实现接口中的方法

public interface ITest {
    // interface 中的 test() 是一个抽象方法
    // 等价:public abstract void test();
    void test();
}
public abstract class AbstractTest implements ITest {
    /**
     * 下面的 public void test() {} 可认为是 ITest 接口中的 test
     * 方法的实现(但不是强制的)。当父接口中的抽象方法的方法签名和抽象类    
     * 中的成员
     * 方法的方法签名一样的时候, 返回值类型也要一样。
     */
    @Override
    public void test() {
        System.out.println("AbstractTest_test()");
    }
}
public class TestTest extends AbstractTest {
    public static void main(String[] args) {
        // AbstractTest_test()
        new TestTest().test();
    }
}

✏️ 一个类可以同时实现多个接口

📒 该类需实现多个接口中的全部抽象方法,除非它是抽象类

✏️ 接口中的属性默认就是常量

public interface ITest {
    // 等价于:public static final int value = 888;
    int value = 888;
}

📒 访问接口中的属性:① 通过接口名访问;② 通过该接口的实现类的类名访问;③ 通过该接口的实现类的实例对象访问

✏️ 一个接口可以继承(extends)多个接口(接口没有继承类的说法)

✏️ 接口只能被 public 关键字修饰,或没有访问修饰符


类实现接口,则有了接口中的常量

interface ITest {
    int value = 666;
}
class ITestImpl implements ITest {
}
public class DemoTest {
    public static void main(String[] args) {
        // 666
        System.out.println(ITest.value);
        // 666
        System.out.println(ITestImpl.value);
        // 666
        System.out.println(new ITestImpl().value); // 不推荐
    }
}

三、继承类和实现接口

✏️【继承类】Dog extends Animal: Dog is a kindof Animal.【狗是一种动物】

✏️【实现接口】GoodStudent implements Teachable: GoodStudent can do something.【好学生会某种能力(被定义在 Teachable 协议中的能力)】

接口和抽象类的选择

四、接口多态

(1) 多态参数

📖 学生购买手机,手机只需有两个功能即可(① 玩游戏;② 刷短视频)

📖 小米手机实现了(implements)InterPhone 接口,所以小米手机可能被购买

📖 华为手机实现了(implements)InterPhone 接口,所以华为手机可能被购买

📖 张思瑞同学购买了华为手机

📖 杨嘉立同学购买了小米手机

📖 两位同学都是 Student 类的实例对象

📖 写代码,实现上面描述的场景❓

public interface InterPhone {
    void playGame(String name);
    void seeVideo(String name);
}
public class XiaoMi implements InterPhone {
    @Override
    public void playGame(String name) {
        System.out.println(name + "_XiaoMi_playGame()");
    }
    @Override
    public void seeVideo(String name) {
        System.out.println(name + "_XiaoMi_seeVideo()");
    }
}
public class HuaWei implements InterPhone {
   @Override
   public void playGame(String name) {
       System.out.println(name + "_HuaWei_playGame()");
   }
   @Override
   public void seeVideo(String name) {
       System.out.println(name + "_HuaWei_seeVideo()");
   }
}
public class Student {
    private InterPhone phone;
    private String name;
    // 多态参数:InterPhone 可指向它的实现类的对象
    // 当传入不同的实现类对象的时候, phone 的指向是多种多样的
    public Student(String name, InterPhone phone) {
        this.name = name;
        this.phone = phone;
    }
    public String getName() {
        return name;
    }
    public InterPhone getPhone() {
        return phone;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Student zsr = new Student("张思瑞", new HuaWei());
        Student yjl = new Student("杨嘉立", new XiaoMi());
        // 张思瑞_HuaWei_playGame()
        zsr.getPhone().playGame(zsr.getName());
        // 杨嘉立_XiaoMi_seeVideo()
        yjl.getPhone().seeVideo(yjl.getName());
    }
}

(2) 多态数组

📖 数组定义的类型是接口数组类型

📖 数组中存放的是接口类型的实现类的类型

public interface InterPhone {
    void playGame(   );
}
public class XiaoMi implements InterPhone {
    @Override
    public void playGame() {
        System.out.println("小米手机打游戏");
    }
    public void cook() {
        System.out.println("小米手机可以炒菜");
    }
}
public class HuaWei implements InterPhone {
    public void playGame(   ) {
        System.out.println("华为手机玩游戏");
    }
    public void eat() {
        System.out.println("华为手机可以填饱肚子");
    }
}
public class Apple implements InterPhone {
    @Override
    public void playGame() {
        System.out.println("苹果手机耍游戏");
    }
    public void sleep() {
        System.out.println("苹果手机可以用来睡觉");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        InterPhone[] phones = new InterPhone[3];
        phones[0] = new HuaWei();
        phones[1] = new XiaoMi();
        phones[2] = new Apple();
0
        for (InterPhone phone : phones) {
            phone.playGame();
            if (phone instanceof HuaWei) {
                HuaWei p = (HuaWei) phone;
                // 华为手机可以填饱肚子
                p.eat();
            }
            if (phone instanceof XiaoMi) {
                XiaoMi p = (XiaoMi) phone;
                // 小米手机可以炒菜
                p.cook();
            }
            if (phone instanceof Apple) {
                Apple p = (Apple) phone;
                // 苹果手机可以用来睡觉
                p.sleep();
            }
        }
        
        /*
            华为手机玩游戏
            华为手机可以填饱肚子
            小米手机打游戏
            小米手机可以炒菜
            苹果手机耍游戏
            苹果手机可以用来睡觉
         */
    }
}

(3) 接口多态传递

📖 ① InterB 接口继承了 InterA 接口;② InterBImpl 类实现 InterB 接口

📖 InterBImpl 类 需要实现 InterB 和 InterA 两个接口中的抽象方法

📖 InterB 和 InterA 两个接口都可以作为父接口引用类型指向 InterBImpl

public interface InterA {
    void a();
}
public interface InterB extends InterA {
    void b();
}
public class InterBImpl implements InterB {
    @Override
    public void b() {
        System.out.println("b");
    }
    @Override
    public void a() {
        System.out.println("a");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        InterBImpl impl = new InterBImpl();
        InterA interA = impl;
        InterB interB = impl;
        // a
        interA.a();
        // b
        interB.b();
        // a
        interB.a();
        // a
        impl.a();
        // b
        impl.b();
    }
}

五、Exercise

实现的接口中的常量名和父类的属性名一样的时候会报错

interface Testable {
    int x = 0;
}
class Apple {
    int x = 1;
}
class Candy extends Apple implements Testable {
    public void printX() {
        // Reference to 'x' is ambiguous
        // both 'Apple.x' and 'Testable.x' match
        // ERROR
        // System.out.println(x);
        // 访问父类(Apple)的【x】
        System.out.println(super.x);
        // 访问父接口(Testable)的【x】
        System.out.println(Testable.x);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        // 1
        // 0
        new Candy().printX();
    }
}

结束!如有错误,请不吝赐教

相关文章
|
1月前
|
Java
【Java】一个简单的接口例子(帮助理解接口+多态)
【Java】一个简单的接口例子(帮助理解接口+多态)
17 0
C4.
|
1月前
|
Java
Java的接口
Java的接口
C4.
21 0
|
1月前
|
Java
JAVA接口
JAVA接口
12 0
|
5天前
|
Java 开发者
探索 Java 的函数式接口和 Lambda 表达式
【4月更文挑战第19天】Java 中的函数式接口和 Lambda 表达式提供了简洁、灵活的编程方式。函数式接口有且仅有一个抽象方法,用于与 Lambda(一种匿名函数语法)配合,简化代码并增强可读性。Lambda 表达式的优点在于其简洁性和灵活性,常用于事件处理、过滤和排序等场景。使用时注意兼容性和变量作用域,它们能提高代码效率和可维护性。
|
5天前
|
Java
Java接口中可以定义哪些方法?
【4月更文挑战第13天】
7 0
Java接口中可以定义哪些方法?
|
7天前
|
设计模式 Java
Java接口与抽象类
Java接口与抽象类
17 0
|
11天前
|
安全 Java 编译器
接口之美,内部之妙:深入解析Java的接口与内部类
接口之美,内部之妙:深入解析Java的接口与内部类
34 0
接口之美,内部之妙:深入解析Java的接口与内部类
|
14天前
|
存储 Java
java接口和内部类
java接口和内部类
|
15天前
|
缓存 安全 Java
Java中函数式接口详解
Java 8引入函数式接口,支持函数式编程。这些接口有单一抽象方法,可与Lambda表达式结合,简化代码。常见函数式接口包括:`Function<T, R>`用于转换操作,`Predicate<T>`用于布尔判断,`Consumer<T>`用于消费输入,`Supplier<T>`用于无参生成结果。开发者也可自定义函数式接口。Lambda表达式使实现接口更简洁。注意异常处理和线程安全。函数式接口广泛应用于集合操作、并行编程和事件处理。提升代码可读性和效率,是现代Java开发的重要工具。
29 0
|
15天前
|
Java 关系型数据库 MySQL
大厂面试题详解:Java抽象类与接口的概念及区别
字节跳动大厂面试题详解:Java抽象类与接口的概念及区别
40 0