【Java篇】以简驭繁:接口的精简与程序的优雅

文章目录

  • 抽象类与接口:Java核心之道(下)
    • 一、前言
    • 二、接口
      • [2.1 接口的概念](#2.1 接口的概念)
      • [2.2 语法规则](#2.2 语法规则)
      • [2.3 接口使用](#2.3 接口使用)
      • [2.4 接口特性](#2.4 接口特性)
      • [2.5 实现多个接口](#2.5 实现多个接口)
      • [2.6 接口间的继承](#2.6 接口间的继承)
      • [2.7 接口使用实例](#2.7 接口使用实例)
        • [2.7.1 给对象数组排序](#2.7.1 给对象数组排序)
        • [2.7.2 使用 Arrays.sort() 排序](#2.7.2 使用 Arrays.sort() 排序)
        • [2.7.3 错误分析](#2.7.3 错误分析)
        • [2.7.4 修正排序问题](#2.7.4 修正排序问题)
        • [2.7.5 运行结果](#2.7.5 运行结果)
        • [2.7.6 自定义排序实现](#2.7.6 自定义排序实现)
      • [2.8 Clonable 接口和深拷贝](#2.8 Clonable 接口和深拷贝)
        • [2.8.1 Clonable 接口介绍](#2.8.1 Clonable 接口介绍)
        • [2.8.2 实现 Cloneable 接口](#2.8.2 实现 Cloneable 接口)
        • [2.8.3 浅拷贝](#2.8.3 浅拷贝)
        • [2.8.4 深拷贝](#2.8.4 深拷贝)
        • [2.8.5 小结](#2.8.5 小结)
    • 三、抽象类与接口的区别
      • [3.1 核心区别](#3.1 核心区别)
      • [3.2 结构组成](#3.2 结构组成)
      • [3.3 使用场景](#3.3 使用场景)
      • [3.4 关系与继承](#3.4 关系与继承)
      • [3.5 关键点总结](#3.5 关键点总结)
    • 四、总结与展望

抽象类与接口:Java核心之道(下)

💬 欢迎讨论:如果你对本篇内容有任何疑问或想深入探讨,欢迎在评论区留言交流!

👍 点赞、收藏与分享:觉得内容有帮助就请点赞、收藏并分享给更多学习Java的小伙伴!

🚀 继续学习之旅:本篇文章将详细讲解接口的基本概念、实现方式以及实际应用,让你在面向对象的世界中进一步提升Java编程技能!

一、前言

在上一篇文章中,我们详细介绍了抽象类与Object类的核心概念,讲解了如何通过抽象类设计模板,以及如何利用Object类中的方法进行对象信息的获取与比较。作为本系列的重要延伸,第二篇文章将聚焦于接口的基本原理和实践应用。

本篇文章将带你了解:

  • 接口的定义和语法规则,了解它作为行为规范在Java中的独特地位;
  • 接口如何帮助我们实现多重继承,打破单继承的限制,使得类可以具备多种特性;
  • 通过USB设备、动物行为等实际案例,展示接口在不同场景下的应用;利用接口实现自定义排序、克隆以及其他高级功能,进一步提升程序的灵活性和可扩展性。

第一篇为你打下了面向对象编程基础,而第二篇则进一步探讨接口如何在实际开发中帮助我们设计出更模块化、解耦合的代码结构。希望你在接下来的阅读中能够进一步掌握接口的精髓,为构建高效的Java程序积累更多经验!

二、接口

2.1 接口的概念

在现实生活中,接口的例子比比皆是:例如笔记本电脑上的USB接口、电源插座等。

  • USB接口: 电脑上的USB口可以插入符合USB协议的U盘、鼠标、键盘等设备。
  • 电源插座: 各种电器(电脑、电视机、电饭煲等)只要符合电源插座的规范就可以使用。

通过这些例子,我们可以看到接口其实就是一套公共的行为规范标准。在实现过程中,只要符合这套标准,不同的设备就能通用。
在Java中,接口被视为多个类的公共规范,同时也是一种引用数据类型。


2.2 语法规则

定义接口的格式与定义类的格式基本相同,主要区别在于将 class 关键字换成 interface 关键字。在创建接口时,常见的命名规则如下:

  1. 接口命名有的一般以大写字母 I 开头;
  2. 命名时常使用形容词词性的单词;
  3. 根据阿里编码规范,接口中的方法和属性尽量不添加多余的修饰符,保持代码简洁。

例如:

java 复制代码
public interface USB {
    // 接口中的方法默认为 public abstract,可省略修饰符
    void openDevice();
    void closeDevice();
}

2.3 接口使用

接口本身不能直接使用,必须由一个实现类来"实现"接口,并提供接口中所有抽象方法的具体实现。

注意:

  • 类与类之间使用 extends 关键字继承,
  • 类与接口之间使用 implements 关键字实现接口。

下面通过一个笔记本电脑使用USB鼠标、USB键盘的例子来说明接口的使用:

  1. USB接口: 包含打开设备、关闭设备的功能;
  2. 笔记本类: 包含开机、关机以及使用USB设备的功能;
  3. 鼠标类: 实现USB接口,并具备点击功能;
  4. 键盘类: 实现USB接口,并具备输入功能。

示例代码如下:

java 复制代码
// USB接口
public interface USB {
    void openDevice();
    void closeDevice();
}

// 鼠标类,实现USB接口
public class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    public void click(){
        System.out.println("鼠标点击");
    }
}

// 键盘类,实现USB接口
public class KeyBoard implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
    public void inPut(){
        System.out.println("键盘输入");
    }
}

// 笔记本类:使用USB设备
public class Computer {
    public void powerOn(){
        System.out.println("打开笔记本电脑");
    }
    public void powerOff(){
        System.out.println("关闭笔记本电脑");
    }
    public void useDevice(USB usb){
        usb.openDevice();
        if(usb instanceof Mouse){
            Mouse mouse = (Mouse)usb;
            mouse.click();
        } else if(usb instanceof KeyBoard){
            KeyBoard keyBoard = (KeyBoard)usb;
            keyBoard.inPut();
        }
        usb.closeDevice();
    }
}

// 测试类
public class TestUSB {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.powerOn();
        // 使用鼠标设备
        computer.useDevice(new Mouse());
        // 使用键盘设备
        computer.useDevice(new KeyBoard());
        computer.powerOff();
    }
}

上述代码展示了如何通过实现接口,让不同的设备(鼠标、键盘)统一遵守USB接口的规范,然后在笔记本电脑中根据不同设备的特性调用相应的方法。


2.4 接口特性

接口具备以下特性:

  1. 引用类型但不能实例化

    接口类型虽然是一种引用数据类型,但不能通过 new 来直接实例化对象。

  2. 所有方法默认是 public abstract

    接口中的每个方法都是隐式的 public abstract,任何其它修饰符(如 private)都不允许使用。

  3. 方法必须由实现类实现

    接口中的方法不能在接口中实现,必须由实现接口的类提供具体实现。如果实现类没有重写所有抽象方法,则该类必须声明为抽象类。

  4. 方法重写时不能降低访问权限

    在实现接口时,重写的方法必须保持 public 访问权限,不能使用比接口中默认的访问权限更低的修饰符。

  5. 接口中可以包含变量,但默认是 public static final

    接口中的变量默认被声明为 public static final,即常量,必须在声明时初始化,且不能被修改:

    java 复制代码
    public interface USB {
        double BRAND = 3.0; // 隐式修饰为 public static final
        void openDevice();
        void closeDevice();
    }
    // 使用时可以直接通过接口名访问
    System.out.println(USB.BRAND);
    // 但不能为 BRAND 赋新值,否则编译报错
  6. 接口中不能有静态代码块和构造方法

    由于接口不能被实例化,自然也就没有构造方法和静态代码块的需求。

  7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

  8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

  9. jdk8 新特性:default 方法

    从 JDK8 开始,接口中可以包含 default 方法,该方法可以有默认的实现,使得接口在向后兼容方面具有更好的扩展性。


2.5 实现多个接口

在Java中,类与类之间是单继承的,一个类只能有一个父类,即Java不支持多继承。然而,一个类可以实现多个接口。通过这种方式,我们能够将多个接口的特性组合在一个类中。下面以动物类为例,展示如何实现多个接口。

我们定义了几个接口,分别表示 "会飞的"、"会跑的" 和 "会游泳的":

java 复制代码
class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }
}

interface IFlying {
    void fly();
}

interface IRunning {
    void run();
}

interface ISwimming {
    void swim();
}

接下来,我们实现几个具体的动物类,如猫、鱼和青蛙。猫是会跑的,鱼是会游的,而青蛙既能跑又能游。

java 复制代码
class Cat extends Animal implements IRunning {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用四条腿跑");
    }
}

class Fish extends Animal implements ISwimming {
    public Fish(String name) {
        super(name);
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在用尾巴游泳");
    }
}

class Frog extends Animal implements IRunning, ISwimming {
    public Frog(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在往前跳");
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在蹬腿游泳");
    }
}

此外,我们还可以设计一种水陆空三栖的动物------鸭子,它既能飞、能跑、又能游泳。

java 复制代码
class Duck extends Animal implements IRunning, ISwimming, IFlying {
    public Duck(String name) {
        super(name);
    }

    @Override
    public void fly() {
        System.out.println(this.name + "正在用翅膀飞");
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在漂在水上");
    }
}

通过上面的代码,我们可以看到,Java 允许一个类实现多个接口,继承的意思是 is-a ,而接口表示的是 具有某种特性

例如:

  • 是一种动物,具有 会跑 的特性;
  • 青蛙 是一种动物,既能跑又能游泳;
  • 鸭子 是一种动物,既能跑、游泳,还能飞。

这种设计的好处是,我们不需要关心具体类型,而只需要关注对象是否具备某种能力。利用多态的特性,我们可以根据接口类型来操作不同的类对象。

假设我们有一个方法 walk,这个方法接受一个实现了 IRunning 接口的对象作为参数,表示"会跑的"的动物:

java 复制代码
public static void walk(IRunning running) {
    System.out.println("我带着伙伴去散步");
    running.run();
}

我们可以调用这个方法:

java 复制代码
Cat cat = new Cat("小猫");
walk(cat);

Frog frog = new Frog("小青蛙");
walk(frog);

执行结果:

java 复制代码
我带着伙伴去散步
小猫正在用四条腿跑
我带着伙伴去散步
小青蛙正在往前跳

即使是一个 Robot (机器人)也能实现 IRunning 接口,我们仍然能够用同样的方法调用:

java 复制代码
class Robot implements IRunning {
    private String name;

    public Robot(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用轮子跑");
    }
}

Robot robot = new Robot("机器人");
walk(robot);

执行结果:

java 复制代码
机器人正在用轮子跑

2.6 接口间的继承

在Java中,接口可以继承其它接口,从而实现接口的多继承。这使得我们可以通过接口继承的方式来复用功能,避免重复代码。

假设我们想要创建一个新的接口 IAmphibious 表示"两栖动物",它包含了 IRunningISwimming 的功能:

java 复制代码
interface IAmphibious extends IRunning, ISwimming {
    // 这个接口继承了 IRunning 和 ISwimming,表示两栖动物具有跑和游的能力
}

接下来,我们可以修改 Frog 类,使其实现 IAmphibious 接口,表示青蛙具备跑和游泳的能力:

java 复制代码
class Frog extends Animal implements IAmphibious {
    public Frog(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在往前跳");
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在蹬腿游泳");
    }
}

通过接口继承,我们将多个接口的功能合并到一个新接口中,并让类实现这个新接口,进一步提升了代码的复用性。

接口间的继承相当于把多个接口合并在一起


2.7 接口使用实例

2.7.1 给对象数组排序

我们可以通过实现 Comparable 接口来对对象数组进行排序。首先,我们定义一个 Student 类,它包含学生的姓名和分数:

java 复制代码
class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }
}

接下来,我们希望对一个学生对象数组进行排序,按照分数的降序排列。可以使用 Arrays.sort() 方法

2.7.2 使用 Arrays.sort() 排序

现在我们可以创建一个学生对象数组,并使用 Arrays.sort() 方法对其进行排序:

java 复制代码
Student[] students = new Student[] {
    new Student("张三", 95),
    new Student("李四", 96),
    new Student("王五", 97),
    new Student("赵六", 92)
};

Arrays.sort(students);
System.out.println(Arrays.toString(students));

运行出错,抛出异常:

java 复制代码
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable
2.7.3 错误分析

如果我们没有让 Student 类实现 Comparable 接口,Arrays.sort() 方法就无法对对象进行排序,因此会抛出 ClassCastException 异常。

2.7.4 修正排序问题

为了解决这个问题,我们必须让 Student 类实现 Comparable 接口,并且重写 compareTo 方法。这样,Arrays.sort() 方法就能够正常工作,并按照我们指定的排序规则进行排序。

通过实现 Comparable 接口并重写 compareTo 方法,我们可以控制排序规则。下面是完整的实现:

java 复制代码
class Student implements Comparable {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }

    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
        if (this.score > s.score) {
            return -1; // 当前对象排在前面
        } else if (this.score < s.score) {
            return 1;  // 当前对象排在后面
        } else {
            return 0;  // 分数相等
        }
    }
}
2.7.5 运行结果

执行修正后的程序,输出的结果是:

java 复制代码
[[王五:97], [李四:96], [张三:95], [赵六:92]]

通过实现 Comparable 接口和 compareTo 方法,我们能够灵活地定义排序规则,从而使用 Arrays.sort() 或自定义排序方法对对象数组进行排序。

2.7.6 自定义排序实现

为了进一步加深对接口的理解,我们可以尝试自己实现一个 sort 方法来完成排序过程,例如使用冒泡排序算法:

java 复制代码
public static void sort(Comparable[] array) {
    for (int bound = 0; bound < array.length; bound++) {
        for (int cur = array.length - 1; cur > bound; cur--) {
            if (array[cur - 1].compareTo(array[cur]) > 0) {
                // 如果顺序不符合要求,交换两个元素的位置
                Comparable tmp = array[cur - 1];
                array[cur - 1] = array[cur];
                array[cur] = tmp;
            }
        }
    }
}

再次执行排序,输出结果如下:

java 复制代码
sort(students);
System.out.println(Arrays.toString(students));
// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]]
[[王五:97], [李四:96], [张三:95], [赵六:92]]

2.8 Clonable 接口和深拷贝

2.8.1 Clonable 接口介绍

在 Java 中,Cloneable 接口是一个非常有用的接口。Object 类中提供了一个 clone() 方法,允许我们创建一个对象的"拷贝"。但需要注意的是,要想合法调用 clone() 方法,类必须实现 Cloneable 接口。如果没有实现该接口,调用 clone() 方法时会抛出 CloneNotSupportedException 异常。

2.8.2 实现 Cloneable 接口

为了使一个类的对象能够被拷贝,我们需要让该类实现 Cloneable 接口,并且重写 clone() 方法。下面是一个简单的例子:

java 复制代码
class Animal implements Cloneable {
    private String name;

    @Override
    public Animal clone() {
        Animal o = null;
        try {
            o = (Animal) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}

public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal animal2 = animal.clone();
        System.out.println(animal == animal2); // 输出结果:false
    }
}

输出结果:

java 复制代码
false

这段代码演示了通过实现 Cloneable 接口并重写 clone() 方法来进行对象的拷贝。当我们调用 animal.clone() 时,会生成 animal 对象的一个副本,但 animalanimal2 仍然是不同的对象(它们的地址不同)。因此,输出为 false

2.8.3 浅拷贝

clone() 方法实现的是一种浅拷贝。浅拷贝的意思是,只有对象本身被复制,引用的对象(如果有的话)并不会被复制,而是仍然指向原来的引用。例如:

java 复制代码
class Money {
    public double m = 99.99;
}

class Person implements Cloneable {
    public Money money = new Money();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class TestDemo3 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person) person1.clone();

        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m);  // 输出:99.99
        System.out.println(person2.money.m);  // 输出:99.99

        // 修改 person2 的 money 值
        person2.money.m = 13.6;

        System.out.println("通过person2修改后的结果");
        System.out.println(person1.money.m);  // 输出:13.6
        System.out.println(person2.money.m);  // 输出:13.6
    }
}

执行结果:

java 复制代码
通过person2修改前的结果
99.99
99.99
通过person2修改后的结果
13.6
13.6

从结果可以看出,通过 clone() 方法拷贝的 Person 对象 person2person1 对象里面的money引用指向相同的 Money 对象。当 person2 修改了 Money 对象的值后,person1Money 对象的值也发生了变化。这是因为 clone() 方法只进行浅拷贝,person2person1 共享同一个 Money 对象。

2.8.4 深拷贝

为了实现深拷贝,我们需要确保不仅拷贝对象本身,还需要拷贝对象引用的其他对象。我们可以在 clone() 方法中手动实现深拷贝。下面是实现深拷贝的例子:

java 复制代码
class Money {
    public double m = 99.99;
}

class Person implements Cloneable {
    public Money money = new Money();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深拷贝:复制 Money 对象
        Person personClone = (Person) super.clone();
        personClone.money = new Money();  // 创建新的 Money 对象
        return personClone;
    }
}

public class TestDemo3 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person) person1.clone();

        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m);  // 输出:99.99
        System.out.println(person2.money.m);  // 输出:99.99

        // 修改 person2 的 money 值
        person2.money.m = 13.6;

        System.out.println("通过person2修改后的结果");
        System.out.println(person1.money.m);  // 输出:99.99
        System.out.println(person2.money.m);  // 输出:13.6
    }
}

执行结果:

java 复制代码
通过person2修改前的结果
99.99
99.99
通过person2修改后的结果
99.99
13.6

在这个例子中,我们在 clone() 方法中对 Money 对象进行了深拷贝,创建了一个新的 Money 对象。这样,person1person2 就不再共享同一个 Money 对象了,修改 person2Money 对象不会影响 person1Money 对象。

2.8.5 小结
  • 浅拷贝:拷贝对象时,如果对象中包含引用类型的成员变量,引用变量不会被拷贝,而是直接引用原对象的地址。
  • 深拷贝:拷贝对象时,不仅拷贝对象本身,还会递归地拷贝对象中引用的其他对象,从而避免引用共享。

通过 Cloneable 接口和重写 clone() 方法,我们可以实现对象的拷贝。具体是浅拷贝还是深拷贝取决于我们如何实现 clone() 方法。


三、抽象类与接口的区别

3.1 核心区别

抽象类和接口的最大区别在于它们可以包含哪些内容:

  • 抽象类 :可以包含普通的方法和字段。子类可以继承这些普通方法和字段,并直接使用这些方法,而不必重新实现它们。抽象类适合那些有共享实现的类,比如 Animal 类,其中包含共享的属性和方法,子类只需继承这些功能。

  • 接口:只能包含抽象方法(Java 8 之后,接口可以有默认方法和静态方法,但其核心作用仍是定义行为)。实现接口的类必须实现接口中的所有抽象方法,接口不能包含普通字段和方法。

因此,抽象类允许子类直接使用其普通方法和字段,而接口要求实现类必须提供方法的具体实现。

3.2 结构组成

区别 抽象类 (abstract) 接口 (interface)
结构组成 普通类 + 抽象方法 抽象方法 + 全局常量
权限 各种权限 public
子类使用 使用 extends 关键字继承抽象类 使用 implements 关键字实现接口
关系 一个抽象类可以实现多个接口 接口不能继承抽象类,但可以使用 extends 关键字继承多个父接口
子类限制 一个子类只能继承一个抽象类 一个子类可以实现多个接口

3.3 使用场景

  • 抽象类的使用场景

    抽象类适合用来描述一类有共性特征的对象,例如动物类 Animal,它包含了一些属性(如 name)和方法(如 eat()),这些方法和属性可以被子类直接使用或重写。抽象类的作用不仅仅是为类提供一种结构,还可以包含实现代码,这样子类就可以直接复用。

    示例:

    java 复制代码
    abstract class Animal {
        protected String name;
    
        public Animal(String name) {
            this.name = name;
        }
    
        public void eat() {
            System.out.println(name + " is eating.");
        }
    
        public abstract void sleep();  // 抽象方法,子类必须实现
    }
    
    class Dog extends Animal {
        public Dog(String name) {
            super(name);
        }
    
        @Override
        public void sleep() {
            System.out.println(name + " is sleeping.");
        }
    }

    这里,Animal 是一个抽象类,包含一个普通方法 eat() 和一个抽象方法 sleep()Dog 类继承 Animal 并实现 sleep() 方法。通过继承,Dog 类可以直接使用 eat() 方法。

  • 接口的使用场景

    接口则是用来定义行为规范的。如果你希望一个类实现某种功能,但不关心这个功能的具体实现,可以使用接口。一个类可以实现多个接口,这样可以在不同的类之间共享功能,而不需要考虑类的层次结构。

    示例:

    java 复制代码
    interface Swimmable {
        void swim();
    }
    
    interface Runnable {
        void run();
    }
    
    class Athlete implements Swimmable, Runnable {
        @Override
        public void swim() {
            System.out.println("Athlete is swimming.");
        }
    
        @Override
        public void run() {
            System.out.println("Athlete is running.");
        }
    }

    在这个例子中,SwimmableRunnable 是两个接口,它们定义了不同的行为,Athlete 类实现了这两个接口,并提供了它们的具体实现。接口的使用允许 Athlete 类同时具备多种能力。

3.4 关系与继承

  • 抽象类的继承:一个类只能继承一个抽象类。因为 Java 不支持多重继承,所以每个类只能有一个父类。如果有多个父类所需的行为,可以通过接口来实现。

  • 接口的继承:一个类可以实现多个接口。如果需要多个不同的功能,可以通过实现多个接口来完成。接口之间也可以继承,允许更加灵活的设计。

    示例:

    java 复制代码
    interface Animal {
        void sound();
    }
    
    interface Mammal extends Animal {
        void giveBirth();
    }
    
    class Dog implements Mammal {
        @Override
        public void sound() {
            System.out.println("Dog barks");
        }
    
        @Override
        public void giveBirth() {
            System.out.println("Dog gives birth");
        }
    }

    在这个例子中,Mammal 接口继承了 Animal 接口,Dog 类同时实现了这两个接口。

3.5 关键点总结

  1. 抽象类:适用于具有共性并且希望在子类中提供具体实现或复用的场景,可以包含普通方法和字段,子类可以继承这些方法和字段。一个类只能继承一个抽象类。

  2. 接口:适用于定义行为规范的场景,不能包含任何实现代码(除非是默认方法或静态方法)。一个类可以实现多个接口,接口之间可以继承。

  3. 继承关系:抽象类是单继承的,接口是多实现的。接口间也可以继承,而抽象类无法继承接口。


四、总结与展望

至此,抽象类与接口就基本介绍完毕了,上一篇文章以抽象类与 Object 类为起点,系统揭示了 Java 面向对象设计的基本理念;随后,本篇围绕接口展开,深入解析了接口作为行为规范在打破单继承局限、实现多态与模块化设计中的独特优势。两篇内容相辅相成:一方面讲解了通过抽象机制与基类方法构建健壮系统的内在逻辑,另一方面展示了接口如何实现灵活扩展和功能组合。站在这一系列研究的节点上,接下来我们将聚焦 String 类,从其存储结构、常用操作到性能优化,全面探讨字符串处理的设计原理与实际应用,力图为 Java 开发者构建更系统、深入的编程实践指南。


以上就是关于【Java篇】以简驭繁:接口的精简与程序的优雅的内容啦,各位大佬有什么问题欢迎在评论区指正,或者私信我也是可以的啦,您的支持是我创作的最大动力!❤️

相关推荐
⑩-1 小时前
Spring 的事务传播行为(Propagation)
java·数据库·spring
没有bug.的程序员1 小时前
K8s 环境中的 JVM 调优实战
java·jvm·spring·云原生·容器·kubernetes
一只乔哇噻1 小时前
java后端工程师+AI大模型开发进修ing(研一版‖day62)
java·开发语言·算法·语言模型
利刃大大1 小时前
【JavaSE】十、ArrayList && LinkedList
java·链表·数组
lsx2024061 小时前
PHP 可用的函数
开发语言
Qiuner1 小时前
Spring 机制六: MVC 全链路源码解析:从 DispatcherServlet 到返回值解析(超硬核源码深度)
java·spring boot·后端·spring·mvc
子一!!1 小时前
并查集(Union-Find)数据结构
java·数据结构·算法
哈库纳玛塔塔1 小时前
MongoDB 数据库 ORM/ODM 新工具
java·数据库·spring boot·mongodb·orm
小满、1 小时前
Redis:GUI 客户端(Redis Insight / Tiny RDM)、基础操作、Spring Boot 连接实现
java·redis·缓存·redis insight·tiny rdm