面向对象编程中的继承与多态:深入理解父类引用指向子类实例

简介: 面向对象编程中的继承与多态:深入理解父类引用指向子类实例

一、引言

    在 Java 编程中,经常会出现使用父类类型的引用指向子类对象的情况。这种情况下,通过父类引用可以调用子类中继承或重写父类的属性和方法,具有一定的多态性和灵活性。本文将介绍父类引用指向子类实例的相关概念、用法和特点。

二、父类引用指向子类实例

概述

    子类可以继承父类中的属性和方法,并且可以重写(override)父类已有的方法。当一个子类对象创建后

  • 可以使用该子类的引用来访问子类中继承或重写父类的属性和方法。
  • 也可以使用父类的引用来指向该子类对象。这种情况下,称之为父类引用指向的是一个子类实例,通过该引用可以访问到子类中继承或重写父类的属性和方法

代码

    假设有一个父类 Animal 和一个子类 Cat,其中 Cat 是 Animal 的子类。父类 Animal 中定义了一个属性 name 以及一个方法 eat(),而子类 Cat 中覆盖了父类的 eat() 方法。现在使用父类引用指向子类对象的方式来创建对象并调用方法:

Animal animal1 = new Cat();
animal1.name = "Tom";
animal1.eat();

    上面代码中使用了Animal 类型的引用 animal1 来指向一个 Cat 类型的对象。通过 animal1 可以调用 Cat 类中继承或重写了父类的属性和方法,例如设置 name 属性为 “Tom”,并调用 eat() 方法输出 “Cat is eating.”。

实现原理

    当父类引用指向子类对象时,父类引用指向了整个子类对象。这包括子类对象中的继承自父类的部分以及子类特有的部分。子类在调用构造函数创建对象时,会先调用父类的构造函数,以便初始化继承自父类的成员。然后再执行子类自己的构造函数,完成对子类特有成员的初始化。

    这里需要注意的是,父类引用指向子类对象后,通过该引用只能访问到父类的成员和子类重写或覆盖的父类成员,而无法直接访问子类特有的成员(如果有)。因为在编译时,编译器只知道该引用的类型是父类,所以只能看到父类中定义的成员。

三、多态性与动态绑定

多态的定义

    多态就是使得同一个行为具有多个不同表现形式或形态的能力。

    举个生活中的例子:对于 打印机的“打印” 行为,使用彩色打印机 “打印” 出来的效果就是彩色的,而使用黑白打印机 “打印” 出来的效果就是黑白的。那么 “打印” 这个行为就是多态的,彩色打印效果和黑白打印效果就是 “打印” 这个行为的两个不同的表现形式。

    当使用父类引用指向子类实例时,可以实现多态。

代码示例

// 父类
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}
// 子类
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("狗在汪汪叫");
    }
}
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("猫在喵喵叫");
    }
}
public class PolymorphismExample {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        animal1.makeSound(); // 输出: 狗在汪汪叫
        animal2.makeSound(); // 输出: 猫在喵喵叫
    }
}

    通过将父类引用指向子类对象,可以通过统一的方式调用makeSound()方法。当animal1引用指向Dog对象时,调用makeSound()方法时会输出"狗在汪汪叫";当animal2引用指向Cat对象时,调用makeSound()方法时会输出"猫在喵喵叫"。这里就体现了多态

多态存在的条件

    多态性是基于 Java 的面向对象编程特性之一,它的核心概念包括多态、继承和重写。在父类引用指向子类实现中,由于子类对象被赋值给了父类类型的引用,从而使得对这个对象的操作具有多态性。

    当然多态存在也是有条件的:

1、继承关系。(没有继承就不要谈多态)

2、子类要重写父类的方法。(不重写方法,子类就没有存在的必要)

3、父类引用指向子类对象。(今天写的重点)

    下图是多态的示意图

多态的发生

    多态到底是如何发生的?如上面那种图所示编译器是如何知道父类 Shape 引用指向的是 Circle 而不是 Triangle 或 Square 呢?

    先来理解一下静态绑定和动态绑定。什么是绑定?将一个方法调用同一个方法主体(也就是方法的具体实现)关联起来的过程称作绑定。

  • 若绑定发生在程序运行前(编译时),叫做静态绑定,也称前期绑定。
  • 在运行时进行的绑定称之为动态绑定。
    在动态绑定中,方法的调用与方法主体的关联是根据实际对象的类型来确定的。

    上图中Shape 即父类,引用类型在编译期可知,不会被改变,而 Circle 作为实例对象类型在运行期才可知,可能会发生变化。所以如果使用前期绑定,在运行之前,编译器只知道有一个 Shape 引用,它无法得知究竟会调用哪个方法。只有在运行时才根据对象的类型自动的进行绑定,所以动态绑定也称运行时绑定。

    另外Java 中除了 static和 final方法(private方法属于 final方法)之外,其他所有方法都是动态绑定。这意味着通常情况下,我们不需要判断动态绑定是否会发生,它是自动发生的。动态绑定是多态的基础。下面细说一下动态绑定

动态绑定

    在访问一个对象的方法时,如果该方法是一个普通方法,那么编译器会根据引用类型来决定要调用哪个方法,而不是根据实际对象类型。

    但是,在访问一个被重写的方法时,其行为就发生了变化,此时编译器将会在运行时确定所要调用的方法。

    动态绑定使得代码与具体对象解耦,允许在不修改现有代码的情况下添加新的子类(通过反射运行时决定实例化哪个子类),从而实现更好的代码复用和维护性。

    因此,只有使用父类引用指向子类对象的情况下,才能够实现多态性和动态绑定的特性。

    回到上面的代码,Animal 类定义了一个 makeSound() 方法,Dog 和 Cat 类继承自 Animal 并重写了该方法。在 main 方法中,通过将父类引用指向子类对象,即 Animal animal1 = new Dog(); 和 Animal animal2 = new Cat();,然后调用 makeSound() 方法。在运行时,根据对象的实际类型,会动态地调用相应的重写方法。

四、补充

父类引用指向子类实例的注意事项

    在使用父类引用指向子类实例时,需要注意以下几点:

  • 变量属性和静态方法没有多态性:变量属性和静态方法不受动态绑定机制的影响,因此无法通过父类引用调用子类中重写或隐藏的变量属性和静态方法。
  • 可以强制类型转换:如果我们需要调用子类特有的属性或方法,可以通过强制类型转换将父类引用转换成子类引用,然后再调用子类特有的属性和方法。但是,强制类型转换可能会导致类型转换异常(ClassCastException),因此需要谨慎使用。
  • 构造函数不能被继承和重写:当创建子类对象时,必须先调用父类的构造函数进行初始化。如果使用父类引用指向子类对象,那么只能通过子类构造函数来完成对象的初始化过程,因为构造函数不能被继承或重写。

父类引用指向子类实例的作用

  • 多态性:父类引用指向子类实现是多态性的一种表现。多态性能够使代码具有更高的灵活性和可扩展性,可以以统一的方式处理不同类型的对象。
  • 统一的接口和规范:通过父类引用指向子类实现,可以定义统一的接口和规范,使得代码更加清晰和易于理解。由于父类和子类之间存在继承关系,父类引用可以作为通用的参数类型传递和操作,从而增强了代码的可读性和可维护性。
  • 代码复用和扩展:父类引用指向子类实现可以促进代码的复用和扩展。通过定义父类,可以将共性的属性和方法提取到父类中,子类通过继承父类来获得这些共性的特征。当需要新增一种子类时,只需编写该子类独有的属性和方法,并且可以使用父类引用来操作新的子类对象,无需修改已有的代码。
  • 适应框架设计和面向接口编程:在许多框架和设计模式中,常常使用父类引用指向子类实现的方式来实现插件式开发和面向接口编程。通过定义父类接口,不同的子类实现该接口,并且可以使用父类引用来操作具体的子类对象,从而实现了松耦合的设计和可插拔的架构。
  • 依赖注入和反转控制:在一些框架和容器中,常常使用父类引用指向子类实现来进行依赖注入和反转控制。通过将具体的子类对象注入到父类引用中,实现了对象间的解耦,提高了代码的可测试性和可维护性。

五、结论

    在Java语言中,通过将父类引用指向子类对象,可以实现多态性,这种实现方式使得代码具有更好的可扩展性和维护性,同时也符合面向对象编程的设计原则。

相关文章
|
5天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
421 125
|
8天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
712 5
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
5天前
|
缓存 人工智能 运维
阿里云618百炼大模型Qwen3.7-Max功能、免费试用、订阅计费、配置接入详解
Qwen3.7-MAX是阿里云百炼平台推出的通义千问3.7系列旗舰大语言模型,专为智能体时代复杂任务打造,依托阿里云全域算力与自研技术,在逻辑推理、长文本处理、代码工程、长周期自主执行等领域达到行业顶尖水平。2026年618期间,该模型推出多重免费试用权益、按量计费5折、订阅套餐优惠等专属福利,覆盖个人开发者、团队与企业全场景需求,以下从核心功能、免费试用、订阅计费、配置接入四方面展开详细解析。
414 123
|
4天前
|
人工智能 自然语言处理 API
阿里云Token Plan团队版解析:功能、三档套餐与省钱订阅指南
阿里云百炼平台推出的Token Plan团队版,是面向企业与团队的AI大模型订阅服务,以Credits为统一计量单位,整合文本与图像生成模型,提供团队管理、数据安全、多工具兼容等核心能力,解决团队零散订阅AI服务的管理混乱、成本失控、数据安全等痛点。本文将从核心定位、套餐详情、计费规则、团队管理、工具兼容、便宜订阅技巧等方面,全面解析Token Plan团队版,帮助企业与团队高效、低成本地使用AI服务。
308 108
|
5天前
|
存储 人工智能 数据可视化
别再手动复制 Skill 了:多 Agent 时代的 Skill 管理方案
多 Agent 场景下 Skill 的统一管理与同步。
256 123
|
19天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
12天前
|
缓存 人工智能 运维
GLM 5.2自托管全流程实战:硬件选型、vLLM/SGLang部署与成本盈亏测算
2026年智谱发布GLM 5.2超大混合专家模型,区别于以往仅开放API的闭源大模型,该模型权重以MIT开源协议对外发布,企业与开发者可完整下载、本地审计、私有化部署,实现数据不出环境、自定义微调、自主调度推理资源。GLM 5.2拥有753B总参数,原生支持百万级上下文窗口,在代码生成、长文档推理、数学逻辑等多项基准测试中对标国际顶尖商用模型,是首款可完整自托管的前沿代码向大模型。
937 0
|
13天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)