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();
    }
}

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

相关文章
|
15天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
33 6
|
15天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
26 2
|
1天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
11 4
|
7天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
5天前
|
Java
Java基础(13)抽象类、接口
本文介绍了Java面向对象编程中的抽象类和接口两个核心概念。抽象类不能被实例化,通常用于定义子类的通用方法和属性;接口则是完全抽象的类,允许声明一组方法但不实现它们。文章通过代码示例详细解析了抽象类和接口的定义及实现,并讨论了它们的区别和使用场景。
|
6天前
|
Java 测试技术 API
Java零基础-接口详解
【10月更文挑战第19天】Java零基础教学篇,手把手实践教学!
15 1
|
11天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
12 3
|
11天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
24 2
|
11天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
23 2
|
11天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
22 1