一文理清类、接口、抽象类之间的继承、实现关系——你不知道的 Java(6)

代码上线就出事,黑锅总往身上背?那是 Java 里那些“你不知道”的细节在作祟!你确定完全掌握 Java 了吗?那些看似基础的操作背后,可能隐藏着你从未触及的深度。《你不知道的 Java》 专栏,专挖这些隐藏知识点,每日一个知识点,助你写出真正健壮、少出问题的代码,从此告别救火队员,安心下班!

在面向对象编程(OOP)中,类(Class)、抽象类(Abstract Class)和接口(Interface)是构建软件系统的基石。它们之间的继承(Inheritance)和实现(Implementation)关系构成了OOP中代码复用、抽象和多态的核心机制。然而,这些关系有时会让人混淆。本文旨在彻底厘清这三者之间所有有效的继承和实现关系,并辅以简要图示和代码示例。

一、核心概念回顾

  1. 类 (Class): 对象的蓝图,包含属性(成员变量)和行为(成员方法)。可以被实例化创建对象。除非被声明为final,否则可以被继承。
  2. 抽象类 (Abstract Class): 不能被实例化的类,主要用于被继承。它可以包含抽象方法(只有声明没有实现)和具体方法(有实现)。子类继承抽象类后,必须实现所有抽象方法,除非子类也是抽象类。使用 abstract 关键字定义。
  3. 接口 (Interface): 定义了一组行为契约(方法签名),通常不包含具体实现(Java 8+ 允许默认方法和静态方法)。类通过实现接口来遵循这个契约。接口完全是抽象的,不能被实例化。使用 interface 关键字定义。

二、核心关系关键字

  • 继承 (Inheritance): 使用 extends 关键字。表示 “is-a” 的关系,子类继承父类的属性和方法(非私有的),实现代码复用和类型扩展。
  • 实现 (Implementation): 使用 implements 关键字(主要在类实现接口时)。表示 “can-do” 或 “has-a-capability” 的关系,类承诺提供接口中定义的所有方法的具体实现。

三、各种继承与实现关系详解

下面我们逐一分析类、抽象类、接口之间所有可能的有效关系:

1. 普通类 继承 普通类 (extends)

  • 关系: 一个普通类可以继承另一个普通类。

  • 规则:

    • Java 中只支持单继承,即一个类最多只能直接继承一个父类。
    • 子类继承父类所有非 private 的成员(变量和方法)。
    • 子类可以重写(Override)父类的方法(需满足重写规则)。
  • 图示:

    extends(单继承)
    A
    // 父类 A 的属性和方法
    +attributeA: int
    +methodA()
    B
    // 子类 B 的属性和方法
    +attributeB: string
    +methodB()
  • 代码示例 (Java):

    // 父类 A
    class Vehicle {
        String brand = "Generic Brand";
        void honk() {
            System.out.println("Tut, tut!");
        }
    }
    
    // 子类 B 继承 父类 A
    class Car extends Vehicle {
        String modelName = "Mustang";
    
        @Override
        void honk() { // 重写父类方法
            System.out.println("Beep, beep!");
        }
    
        void display() {
            System.out.println("Brand: " + brand + ", Model: " + modelName); // 访问继承的 brand
        }
    }
    
    // 使用
    Car myCar = new Car();
    myCar.honk(); // 输出: Beep, beep!
    myCar.display(); // 输出: Brand: Generic Brand, Model: Mustang
    

2. 普通类 继承 抽象类 (extends)

  • 关系: 一个普通类可以继承一个抽象类。
  • 规则:
    • 同样遵循单继承原则。
    • 子类必须实现父抽象类中所有的抽象方法。如果子类没有实现所有抽象方法,那么子类也必须声明为抽象类。
    • 子类继承父抽象类的非抽象方法和成员变量。
  • 图示:
    extends (单继承)
    抽象父类A
    <> // 标记为抽象类
    +String color
    +abstract double getArea()
    +void setColor(String color)
    子类B
    +double radius
    +double getArea()
    +Circle(double radius, String color)
  • 代码示例 (Java):
    // 抽象父类 A
    abstract class Shape {
        String color;
        abstract double getArea(); // 抽象方法
    
        void setColor(String color) { // 具体方法
            this.color = color;
        }
    }
    
    // 普通子类 B 继承 抽象父类 A
    class Circle extends Shape {
        double radius;
    
        Circle(double radius, String color) {
            this.radius = radius;
            setColor(color); // 调用继承的具体方法
        }
    
        @Override
        double getArea() { // 必须实现抽象方法
            return Math.PI * radius * radius;
        }
    }
    
    // 使用
    Circle myCircle = new Circle(5.0, "Red");
    System.out.println("Area: " + myCircle.getArea()); // 输出: Area: 78.539...
    System.out.println("Color: " + myCircle.color); // 输出: Color: Red
    

3. 普通类 实现 接口 (implements)

  • 关系: 一个普通类可以实现一个或多个接口。

  • 规则:

    • 支持多实现,一个类可以同时实现多个接口。
    • 必须实现所实现接口中定义的所有抽象方法(Java 8 之前的接口只有抽象方法)。
    • 如果一个类实现了多个接口,且这些接口包含签名相同的默认方法,类必须显式重写该默认方法以解决冲突。
  • 图示:

    implements
    implements
    «Interface»
    I1
    +methodA()
    «Interface»
    I2
    +methodB()
    C
    +methodA()
    +methodB()
  • 代码示例 (Java):

    // 接口 I1
    interface Animal {
        void eat();
        void sleep();
    }
    
    // 接口 I2
    interface Pet {
        void play();
    }
    
    // 实现类 C 实现 I1 和 I2
    class Dog implements Animal, Pet {
        @Override
        public void eat() {
            System.out.println("Dog eats bone.");
        }
    
        @Override
        public void sleep() {
            System.out.println("Dog sleeps in kennel.");
        }
    
        @Override
        public void play() {
            System.out.println("Dog plays fetch.");
        }
    }
    
    // 使用
    Dog myDog = new Dog();
    myDog.eat();
    myDog.sleep();
    myDog.play();
    

4. 抽象类 继承 普通类 (extends)

  • 关系: 一个抽象类可以继承一个普通类。
  • 规则:
    • 遵循单继承原则。
    • 抽象子类继承父类的所有非 private 成员。
    • 抽象子类可以不实现任何方法,也可以添加新的抽象方法或具体方法。
  • 图示:
    extends (单继承)
    A
    +void concreteMethodA()
    B
    <> // 标记为抽象类
    +void concreteMethodA()
    +abstract void newAbstractMethodB()
  • 代码示例 (Java):
    // 普通父类 A
    class Machine {
        void start() {
            System.out.println("Machine started.");
        }
    }
    
    // 抽象子类 B 继承 普通父类 A
    abstract class Printer extends Machine {
        abstract void printDocument(String doc); // 添加新的抽象方法
    
        void loadPaper() {
            System.out.println("Paper loaded.");
        }
    }
    
    // 另一个具体类继承 Printer
    class LaserPrinter extends Printer {
         @Override
         void printDocument(String doc) {
             System.out.println("Laser printing: " + doc);
         }
    }
    
    // 使用
    LaserPrinter lp = new LaserPrinter();
    lp.start(); // 继承自 Machine
    lp.loadPaper(); // 定义在 Printer
    lp.printDocument("MyReport.pdf"); // 实现自 Printer 的抽象方法
    

5. 抽象类 继承 抽象类 (extends)

  • 关系: 一个抽象类可以继承另一个抽象类。
  • 规则:
    • 遵循单继承原则。
    • 子抽象类继承父抽象类的所有成员(包括抽象方法和具体方法)。
    • 子抽象类不需要必须实现父抽象类中的抽象方法。它可以选择实现部分或全部,或者完全不实现,将实现责任继续传递给它的具体子类。子抽象类也可以定义新的抽象方法。
  • 图示:
    [父类 A (Abstract Class)] {abstract methodX()}
            ↑
            | extends (单继承)
    [子类 B (Abstract Class)]
    
  • 代码示例 (Java):
    // 父抽象类 A
    abstract class AbstractWorker {
        abstract void work(); // 抽象方法 1
        void takeBreak() { // 具体方法
            System.out.println("Taking a 15-minute break.");
        }
    }
    
    // 子抽象类 B 继承 父抽象类 A
    abstract class TeamLead extends AbstractWorker {
        // 可以选择不实现 work() 方法
        abstract void assignTask(); // 添加新的抽象方法
    
        @Override
        void takeBreak() { // 可以重写具体方法
             System.out.println("Team lead takes a 5-minute coffee break.");
        }
    }
    
    // 具体类继承 TeamLead
    class SoftwareLead extends TeamLead {
        @Override
        void work() { // 必须实现来自 AbstractWorker 的 work()
            System.out.println("Lead is coordinating the team.");
        }
    
        @Override
        void assignTask() { // 必须实现来自 TeamLead 的 assignTask()
            System.out.println("Assigning coding tasks to developers.");
        }
    }
    
    // 使用
    SoftwareLead sl = new SoftwareLead();
    sl.work();
    sl.assignTask();
    sl.takeBreak(); // 调用重写后的方法
    

6. 抽象类 实现 接口 (implements)

  • 关系: 一个抽象类可以实现一个或多个接口。
  • 规则:
    • 支持多实现
    • 抽象类实现接口时,不必实现接口中的所有抽象方法。它可以选择实现部分或全部方法,或者完全不实现,将实现的责任留给它的具体子类。
  • 图示:
    [接口 I1] {methodA()}   [接口 I2] {methodB()}
        ↑                      ↑
        | implements (多实现)  | implements
        +----------------------+
                   |
    [抽象实现类 C (Abstract Class)] {can implement methodA(), or leave abstract; must declare methodB() if not implemented}
    
  • 代码示例 (Java):
    // 接口 I1
    interface Runnable {
        void run();
    }
    // 接口 I2
    interface Closable {
        void close();
    }
    
    // 抽象类 C 实现 I1 和 I2
    abstract class AbstractTaskRunner implements Runnable, Closable {
        // 选择实现 run() 方法
        @Override
        public void run() {
            System.out.println("Task is running...");
            performTask();
            System.out.println("Task finished.");
        }
    
        // 定义一个新的抽象方法,具体任务由子类定义
        abstract void performTask();
    
        // 选择不实现 close() 方法,将其留给具体子类
        // public abstract void close(); // (隐式地,因为接口方法是 public abstract)
    }
    
    // 具体子类
    class FileProcessor extends AbstractTaskRunner {
        @Override
        void performTask() {
            System.out.println("Processing file...");
        }
    
        @Override
        public void close() { // 必须实现未被抽象父类实现的接口方法
            System.out.println("Closing file resources.");
        }
    }
    
    // 使用
    FileProcessor fp = new FileProcessor();
    fp.run();
    fp.close();
    

7. 接口 继承 接口 (extends)

  • 关系: 一个接口可以继承一个或多个其他接口。
  • 规则:
    • 接口之间的继承支持多继承
    • 子接口会继承父接口中定义的所有方法(以及常量)。
    • 如果一个类实现了子接口,那么它必须实现子接口及其所有父接口中定义的所有抽象方法。
  • 图示:
    [父接口 I1] {methodA()}   [父接口 I2] {methodB()}
         ↑                      ↑
         | extends (多继承)     | extends
         +----------------------+
                    |
            [子接口 I3] {inherits methodA(), methodB(), can add methodC()}
    
  • 代码示例 (Java):
    // 父接口 I1
    interface Serializable {
        // (标记接口,或包含方法)
    }
    
    // 父接口 I2
    interface Loggable {
        void log(String message);
    }
    
    // 子接口 I3 继承 I1 和 I2
    interface PersistentLoggable extends Serializable, Loggable {
        void saveState(); // 新增方法
    }
    
    // 实现类实现子接口 I3
    class UserSession implements PersistentLoggable {
        @Override
        public void log(String message) {
            System.out.println("LOG: " + message);
        }
    
        @Override
        public void saveState() {
            System.out.println("Saving user session state...");
            log("Session state saved."); // 可以调用继承的 log 方法
        }
        // Serializable 是标记接口,无需实现方法
    }
    
    // 使用
    UserSession session = new UserSession();
    session.saveState();
    

不存在的关系

  • 类/抽象类 extends 接口: 这是不允许的。类只能 implements (实现) 接口,不能 extends (继承) 接口。继承意味着继承实现(或部分实现),而接口(主要)只定义契约。
  • 接口 extends 类/抽象类: 这是不允许的。接口只能继承其他接口,不能继承类或抽象类。接口代表纯粹的契约,不应包含类的具体实现或状态。
  • 接口 implements … : 接口之间是 extends 关系,不是 implements

四、总结

子类型 (Child) ↓父类型 (Parent) →关系 (Relationship)数量 (Multiplicity)关键字 (Keyword)备注 (Notes)
普通类 (Class)普通类 (Class)继承 (Inheritance)单个 (Single)extends继承非私有成员,可重写方法。
普通类 (Class)抽象类 (Abstract)继承 (Inheritance)单个 (Single)extends必须实现所有父抽象方法。
普通类 (Class)接口 (Interface)实现 (Implementation)多个 (Multiple)implements必须实现所有接口方法(抽象的)。
抽象类 (Abstract)普通类 (Class)继承 (Inheritance)单个 (Single)extends继承非私有成员,可添加抽象方法。
抽象类 (Abstract)抽象类 (Abstract)继承 (Inheritance)单个 (Single)extends继承成员,无需实现父抽象方法,可添加新抽象方法。
抽象类 (Abstract)接口 (Interface)实现 (Implementation)多个 (Multiple)implements无需实现所有接口方法,可将实现责任传递给子类。
接口 (Interface)接口 (Interface)继承 (Inheritance)多个 (Multiple)extends继承父接口所有方法签名。
接口 (Interface)类/抽象类不允许N/AN/A接口不能继承类或抽象类。
类/抽象类接口 (Interface)不允许继承N/AN/A类/抽象类通过 implements 实现接口,不是 extends 继承。

五、结语

理解类、抽象类和接口之间的继承与实现关系是掌握面向对象设计的关键。

  • 类继承 (extends Class/Abstract Class) 主要用于代码复用和建立强 “is-a” 的类型层次结构(单继承)。
  • 接口实现 (implements Interface) 主要用于定义契约和能力,实现多态和解耦(多实现)。
  • 抽象类 (abstract class) 介于两者之间,提供了一种共享部分实现和强制子类实现某些行为的机制(单继承)。
  • 接口继承 (extends Interface) 用于组合和扩展契约(多继承)。

通过合理运用这些关系,可以构建出结构清晰、可扩展、易于维护的软件系统。希望本文能帮助你彻底理清这些概念及其用法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值