0

0

如何在Java中实现类的继承

P粉602998670

P粉602998670

发布时间:2025-09-21 11:54:01

|

456人浏览过

|

来源于php中文网

原创

Java通过extends实现单继承,确保代码复用与类型安全;构造器通过super调用父类初始化;为避免菱形问题不支持多重继承,但可通过接口实现多行为组合;优先使用组合而非继承以降低耦合。

如何在java中实现类的继承

在Java中,实现类的继承主要通过使用

extends
关键字。它允许一个类(子类或派生类)从另一个类(父类或基类)继承其字段和方法,从而在它们之间建立一种“is-a”(是……一种)的关系,这极大地促进了代码的重用和扩展性。

解决方案

要在Java中实现继承,你只需要在子类的声明中使用

extends
关键字,后跟父类的名称。这在我看来,是Java面向对象三大特性中最直观也最常用的一环。

例如,我们有一个

Animal
类,它有一些基本的行为和属性:

class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
        System.out.println("Animal " + name + " created.");
    }

    public void eat() {
        System.out.println(name + " is eating.");
    }

    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

现在,我们想创建一个

Dog
类,它是一种特殊的
Animal
Dog
会继承
Animal
name
属性和
eat()
sleep()
方法,同时它可能还有自己特有的行为,比如
bark()

立即学习Java免费学习笔记(深入)”;

class Dog extends Animal {
    public Dog(String name) {
        // 调用父类的构造器
        super(name); 
        System.out.println("Dog " + name + " created.");
    }

    public void bark() {
        System.out.println(name + " is barking.");
    }

    // 方法重写:子类提供父类方法的具体实现
    @Override
    public void eat() {
        System.out.println(name + " is happily eating dog food.");
    }
}

在这个例子中:

  • Dog extends Animal
    表明
    Dog
    继承自
    Animal
  • super(name)
    是一个关键点,它用于调用父类
    Animal
    的构造器来初始化继承自父类的
    name
    属性。在子类构造器中,
    super()
    调用必须是第一条语句。
  • @Override
    注解表明
    eat()
    方法是重写了父类的方法。这是可选的,但强烈建议使用,它能帮助编译器检查你是否正确地重写了方法。
  • Dog
    类现在拥有
    name
    属性、
    eat()
    sleep()
    方法(继承自
    Animal
    )以及它自己的
    bark()
    方法。

继承的本质,说白了就是一种代码复用和类型体系的构建。子类可以访问父类中

public
protected
修饰的成员,但不能直接访问
private
成员。

Java继承中构造器是如何工作的?

这是一个经常让人感到困惑的地方,毕竟构造器不像普通方法那样能被直接继承。其实,在Java的继承体系中,子类构造器在执行之前,总是会隐式或显式地调用其父类的构造器。这是为了确保父类部分的状态在子类对象完全构建之前被正确初始化。

具体来说:

  1. 隐式调用父类无参构造器: 如果子类构造器中没有显式地调用
    super()
    super(...)
    ,那么编译器会自动在子类构造器的第一行插入一个对父类无参构造器
    super()
    的调用。这意味着,如果你的父类没有无参构造器,或者你只定义了带参数的构造器,那么子类就必须显式地调用父类的某个带参构造器。
  2. 显式调用父类构造器: 当父类没有无参构造器,或者你需要调用父类的特定构造器来初始化某些继承的属性时,你必须在子类构造器的第一行使用
    super(参数列表)
    来显式调用父类的构造器。

让我们看一个例子,假设

Animal
类只有一个带参数的构造器:

class Animal {
    String name;
    int age;

    public Animal(String name, int age) { // 只有一个带参数的构造器
        this.name = name;
        this.age = age;
        System.out.println("Animal " + name + " (age " + age + ") created.");
    }
    // 注意:这里没有默认的无参构造器
}

class Cat extends Animal {
    String breed;

    public Cat(String name, int age, String breed) {
        // 必须显式调用父类的构造器,因为父类没有无参构造器
        super(name, age); 
        this.breed = breed;
        System.out.println("Cat " + name + " (breed " + breed + ") created.");
    }

    public void meow() {
        System.out.println(name + " is meowing.");
    }
}

// 使用
// Cat myCat = new Cat("Whiskers", 3, "Siamese");
// 输出:
// Animal Whiskers (age 3) created.
// Cat Whiskers (breed Siamese) created.

如果

Cat
类的构造器中没有
super(name, age);
,编译器就会报错,因为它无法找到
Animal
的无参构造器来隐式调用。这种机制确保了父类在子类实例化时能够得到正确的初始化,避免了潜在的对象状态不一致问题。

Java中多重继承为何不被直接支持?接口如何弥补这一限制?

Java在类的继承上只支持单继承,也就是说一个类只能直接继承一个父类。这与C++等语言支持多重继承形成了鲜明对比。Java选择单继承,主要是为了避免“菱形问题”(Diamond Problem)带来的复杂性和歧义。

想象一下,如果一个类

D
同时继承了
B
C
,而
B
C
又都继承了
A
,并且
A
中有一个方法
m()
。那么当
D
调用
m()
时,它应该调用
B
版本的
m()
还是
C
版本的
m()
呢?这就会造成编译器的困扰,增加了语言设计的复杂性,也让代码的行为变得难以预测和维护。Java的设计者们为了语言的简洁性、安全性和可维护性,果断放弃了类的多重继承。

ASP.NET 4.0电子商城
ASP.NET 4.0电子商城

在现实生活中的购物过程,购物者需要先到商场,找到指定的产品柜台下,查看产品实体以及标价信息,如果产品合适,就将该产品放到购物车中,到收款处付款结算。电子商务网站通过虚拟网页的形式在计算机上摸拟了整个过程,首先电子商务设计人员将产品信息分类显示在网页上,用户查看网页上的产品信息,当用户看到了中意的产品后,可以将该产品添加到购物车,最后使用网上支付工具进行结算,而货物将由公司通过快递等方式发送给购物者

下载

然而,在实际开发中,我们确实经常需要一个类能够拥有多种不同的行为或“角色”。Java通过接口(Interface)来优雅地解决了这个问题。

接口是Java中定义行为规范的抽象类型。它只包含抽象方法(在Java 8以后可以有默认方法和静态方法)和常量。一个类可以实现(

implements
)一个或多个接口,从而获得这些接口定义的所有行为能力。

interface Flyable {
    void fly(); // 抽象方法
    default void glide() { // 默认方法 (Java 8+)
        System.out.println("Gliding through the air.");
    }
}

interface Swimmable {
    void swim(); // 抽象方法
}

class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Duck is flying with its wings.");
    }

    @Override
    public void swim() {
        System.out.println("Duck is swimming in the pond.");
    }

    // 继承了Flyable接口的glide默认方法,也可以选择重写
}

// 使用
// Duck myDuck = new Duck();
// myDuck.fly();
// myDuck.swim();
// myDuck.glide();

在这个例子中,

Duck
类同时具备了
Flyable
Swimmable
两种能力,但它并没有继承两个父类。接口实现了“多重继承行为”的效果,而避免了“菱形问题”带来的数据和状态冲突。接口强调的是“能做什么”,而类继承强调的是“是什么”。通过接口,Java在保持类体系清晰的同时,提供了足够的灵活性来构建复杂而富有行为的对象。

何时应该使用继承?组合(Composition)与继承相比有何优势?

关于何时使用继承,这是一个经典的软件设计问题,也是很多新手容易踩坑的地方。我个人的经验是,只有当存在明确的“is-a”关系时,才应该考虑使用继承。 也就是说,如果子类真的是父类的一种特殊类型,并且子类在概念上完全符合父类的定义,那么继承是合适的。

例如:

  • Car
    is-a
    Vehicle
    (汽车是交通工具的一种)
  • Dog
    is-a
    Animal
    (狗是动物的一种)
  • Manager
    is-a
    Employee
    (经理是员工的一种)

继承的主要优点在于代码复用和多态性。你可以将通用逻辑放在父类中,子类直接继承使用;同时,通过父类引用指向子类对象,可以实现灵活的运行时行为。

然而,继承并非万能药,它也有明显的缺点,特别是当滥用时:

  • 紧耦合: 子类与父类之间形成了强烈的依赖关系。父类的任何改变都可能影响到所有子类,这被称为“脆弱的基类问题”(Fragile Base Class Problem)。
  • 设计僵化: 继承关系在编译时就确定了,运行时无法改变。如果需求变化,可能需要重构整个继承体系。
  • 继承层次过深: 复杂的继承链会使代码难以理解和维护。

正因为这些缺点,软件设计中还有一个同样重要的原则叫做“优先使用组合而非继承”(Prefer Composition over Inheritance)

组合(Composition)强调的是“has-a”关系。一个类通过包含另一个类的实例作为其成员来复用其功能,而不是继承。

// 假设有一个Engine类
class Engine {
    public void start() {
        System.out.println("Engine started.");
    }
    public void stop() {
        System.out.println("Engine stopped.");
    }
}

// 使用组合构建Car类
class Car {
    private Engine engine; // Car has an Engine

    public Car() {
        this.engine = new Engine(); // Car包含一个Engine实例
    }

    public void startCar() {
        engine.start();
        System.out.println("Car started.");
    }

    public void stopCar() {
        engine.stop();
        System.out.println("Car stopped.");
    }
}

// 使用
// Car myCar = new Car();
// myCar.startCar();
// myCar.stopCar();

组合的优势在于:

  • 松耦合:
    Car
    类与
    Engine
    类之间的耦合度较低。
    Car
    只需要知道
    Engine
    提供了
    start()
    stop()
    方法,而不需要了解
    Engine
    的内部实现细节。即使
    Engine
    的内部实现发生变化,只要接口不变,
    Car
    就不受影响。
  • 更高的灵活性: 组合关系可以在运行时动态改变。例如,
    Car
    可以根据需要更换不同类型的
    Engine
    实例。
  • 更简单的层次结构: 避免了复杂的继承链,使得系统设计更加扁平化和易于理解。

在我看来,选择继承还是组合,很大程度上取决于你试图建模的关系。如果确实是“is-a”的分类关系,并且父类提供了稳定的核心行为,继承是高效的。但如果只是想复用某个类的功能,或者想让一个对象拥有另一个对象的能力,那么组合通常是更灵活、更健壮的选择。很多时候,通过接口和组合的结合使用,能够构建出比纯粹继承体系更灵活、更易于维护的系统。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1500

2023.10.24

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

56

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

52

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1079

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

169

2025.10.17

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.7万人学习

Java 教程
Java 教程

共578课时 | 52.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号