(二十一)Java 之多态

2024-06-18 17:36
文章标签 java 多态 二十一

本文主要是介绍(二十一)Java 之多态,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一. 前言

二. 多态

2.1. 实例入手

2.2. 虚方法

三. 多态的实现方式

四. 课后习题


一. 前言

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

    多态性是对象多种表现形式的体现。

    比如我们说“宠物”这个对象,它就有很多不同的表达或实现,比如有小猫、小狗、蜥蜴等等。那么我到宠物店说“请给我一只宠物”,服务员给我小猫、小狗或者蜥蜴都可以,我们就说“宠物”这个对象就具备多态性。

    接下来让我们通过实例来了解 Java 的多态。

二. 多态

2.1. 实例入手

public interface Vegetarian {}public class Animal {}public class Deer extends Animal implements Vegetarian {}

因为 Deer 类具有多重继承,所以它具有多态性。以上实例解析如下:

  • 一个 Deer IS-A(是一个)Animal。
  • 一个 Deer IS-A(是一个)Vegetarian。
  • 一个 Deer IS-A(是一个)Deer。
  • 一个 Deer IS-A(是一个)Object。

    在 Java 中,所有的对象都具有多态性,因为任何对象都能通过 IS-A 测试类型和 Object 类。

    访问一个对象的唯一方法就是通过引用型变量。

    引用型变量只能有一种类型,一旦被声明,引用型变量的类型就不能被改变了。

    引用型变量不仅能够被重置为其他对象,前提是这些对象没有被声明为 final。还可以引用和它类型相同的或者相兼容的对象。它可以声明为类类型或者接口类型。

    当我们将引用型变量应用于 Deer 对象的引用时,下面的声明是合法的:

Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

所有的引用型变量 d、a、v、o 都指向堆中相同的 Deer 对象。

2.2. 虚方法

我们将介绍在 Java 中,当设计类时,被重写的方法的行为怎样影响多态性。

我们已经讨论了方法的重写,也就是子类能够重写父类的方法。

当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。

要想调用父类中被重写的方法,则必须使用关键字 super

/* 文件名 : Employee.java */
public class Employee {private String name;private String address;private int number;public Employee(String name, String address, int number) {System.out.println("Constructing an Employee");this.name = name;this.address = address;this.number = number;}public void mailCheck() {System.out.println("Mailing a check to " + this.name+ " " + this.address);}public String toString() {return name + " " + address + " " + number;}public String getName() {return name;}public String getAddress() {return address;}public void setAddress(String newAddress) {address = newAddress;}public int getNumber() {return number;}
}

假设下面的类继承 Employee 类:

/* 文件名 : Salary.java */
public class Salary extends Employee {private double salary; // Annual salarypublic Salary(String name, String address, int number, double salary) {super(name, address, number);setSalary(salary);}public void mailCheck() {System.out.println("Within mailCheck of Salary class ");System.out.println("Mailing check to " + getName()+ " with salary " + salary);}public double getSalary() {return salary;}public void setSalary(double newSalary) {if (newSalary >= 0.0) {salary = newSalary;}}public double computePay() {System.out.println("Computing salary pay for " + getName());return salary / 52;}
}

现在我们仔细阅读下面的代码,尝试给出它的输出结果:

/* 文件名 : VirtualDemo.java */
public class VirtualDemo {public static void main(String[] args) {Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);System.out.println("Call mailCheck using Salary reference --");s.mailCheck();System.out.println("\n Call mailCheck using Employee reference--");e.mailCheck();}
}

运行结果:

Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.0

例子中,我们实例化了两个 Salary 对象。一个使用 Salary 引用 s,另一个使用 Employee 引用。

编译时,编译器检查到 mailCheck() 方法在 Salary 类中的声明。

在调用 s.mailCheck() 时,Java 虚拟机(JVM)调用 Salary 类的 mailCheck() 方法。

因为 e 是 Employee 的引用,所以调用 e 的 mailCheck() 方法则有完全不同的结果。

当编译器检查 e.mailCheck() 方法时,编译器检查到 Employee 类中的 mailCheck() 方法。

在编译的时候,编译器使用 Employee 类中的 mailCheck() 方法验证该语句, 但是在运行的时候,Java 虚拟机(JVM)调用的是 Salary 类中的 mailCheck() 方法。

该行为被称为虚拟方法调用,该方法被称为虚拟方法。

Java 中所有的方法都能以这种方式表现,借此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。

三. 多态的实现方式

方式一:重写

这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:《(二十)Java 面向对象之重载(Overload)与重写(Override)》。

方式二:接口

  1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
  2. Java 中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。

方式三:抽象类和抽象方法

将在下一篇博文中介绍。

四. 课后习题

1. 编写程序实现乐手弹奏乐器。乐手可以弹奏不同的乐器从而发出不同的声音。

2. 编写程序实现主人喂养宠物和跟宠物玩耍的场景。定义宠物类 Pet,宠物都需要吃东西,跟主人玩。定义狗类 Dog、猫类 Cat、Dolphin 海豚类继承 Pet 宠物类。狗狗吃骨头、猫咪吃老鼠、海豚吃乌贼。

3. 写三个具体的类(猫、狗、羊),它们都是动物类的子类,并重写父类的成员方法。编写测试类,随机产生三种具体动物,调用叫声这个方法。

4. 豆豆家养了两只家禽 Poultry:一只鸡 Chicken 和一只鸭 Duck。请再写一个类 Master,有一个方 cry()。

这篇关于(二十一)Java 之多态的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072655

相关文章

Spring boot整合dubbo+zookeeper的详细过程

《Springboot整合dubbo+zookeeper的详细过程》本文讲解SpringBoot整合Dubbo与Zookeeper实现API、Provider、Consumer模式,包含依赖配置、... 目录Spring boot整合dubbo+zookeeper1.创建父工程2.父工程引入依赖3.创建ap

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件