深入解析Java多态进阶学习

news2024/11/27 16:39:11
目录
  • 1.动态绑定机制
    • 实例A
    • 实例B
    • 实例C
  • 2.多态数组
  • 3.多态数组的高阶用法
  • 4.多态参数
  • 5.多态参数的高阶用法

1.动态绑定机制

java的动态绑定机制非常重要

实例A

我们来看一个实例:

阅读上面的代码,请说明下面的程序将输出什么结果:

程序将会输出40和30,这个实例很简单,直接看运行类型即可,该代码的运行类型为B,所以会调用B类的方法

实例B

我们将上面的代码变通一下,将子类中的如下代码块注销:

随后继承机制会访问父类的sum方法:

那么这里有一个问题,此处的getI(),会执行子类的还是父类的呢?

当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定

代码的运行类型依然是B,所以此处会执行子类的getI()方法,结果输出为30

实例C

现在我们再变通以下上面的代码

再将子类中如下的代码块注销:

继承机制会执行父类的sum1方法:

那么这里有一个问题,此处的i,会使用子类的还是父类的呢?

属性没有动态绑定机制,哪里声明,哪里使用(使用当前类的)

此处的i在父类进行声明,所以会选用父类的i属性,结果为20

2.多态数组

定义:

数组的定义类型为父类类型,但是保存的实际元素类型为子类类型

Person父类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

/**

 * 多态数组父类

 */

public class Person {

    private String name;

    private int age;

    public Person(String name, int age) {

        this.name = name;

        this.age = age;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public String say() {

        return name + '\t' + age;

    }

}

Student子类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

 * 多态数组学生子类

 */

public class Student extends Person{

    private double score;

    public Student(String name, int age, double score) {

        super(name, age);

        this.score = score;

    }

    // 重写父类的say方法

    public String say() {

        return super.say() + '\t' + score;

    }

}

Teacher子类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

/**

 * 多态数组教师子类

 */

public class Teacher extends Person {

    private double sal;

    public Teacher(String name, int age, double sal) {

        super(name, age);

        this.sal = sal;

    }

    public double getSal() {

        return sal;

    }

    public void setSal(double sal) {

        this.sal = sal;

    }

    public String say() {

        return super.say() + '\t' + sal;

    }

}

测试多态数组的使用:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class Test {

    public static void main(String[] args) {

        // 多态数组的使用

        Person[] persons = new Person[5];

        persons[0] = new Person("dahe",20);

        persons[1] = new Student("wangwei",11,100);

        persons[2] = new Student("zhangsan",12,60);

        persons[3] = new Teacher("wang",33,15000);

        persons[4] = new Teacher("li",55,25000);

        // 循环遍历多态数组,调用say方法

        for (int i = 0; i < persons.length; i++) {

            String out = persons[i].say(); // 动态绑定机制,编译类型永远都是Person

            // 运行类型是根据实际情况由JVM机决定

            System.out.println(out);

        }

    }

}

输出:

dahe    20
wangwei    11    100.0
zhangsan    12    60.0
wang    33    15000.0
li    55    25000.0

3.多态数组的高阶用法

现在,教师子类新增了教学方法:

?

1

2

3

public void teach() {

    System.out.println("老师:" + getName() + "正在讲课!");

}

学生子类新增了学习方法:

?

1

2

3

public void study() {

    System.out.println("学生:" + getName() + "正在学习!");

}

那么,有没有办法通过多态数组来访问他们子类对应的独有的方法呢?事实上,可以通过巧妙使用instanceof来解决:

变通一下,改变多态数组的循环操作:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 循环遍历多态数组,调用say方法

for (int i = 0; i < persons.length; i++) {

    String out = persons[i].say(); // 动态绑定机制,编译类型永远都是Person

    // 运行类型是根据实际情况由JVM机决定

    System.out.println(out);

    if (persons[i] instanceof Student) {

        // 向下转型

        Student student = (Student) persons[i];

        student.study();

    } else if (persons[i] instanceof Teacher) {

        Teacher teacher = (Teacher) persons[i];

        teacher.teach();

    }

}

输出:

dahe    20
wangwei    11    100.0
学生:wangwei正在学习!
zhangsan    12    60.0
学生:zhangsan正在学习!
wang    33    15000.0
老师:wang正在讲课!
li    55    25000.0
老师:li正在讲课!

大功告成!多态数组即强大又完美!

4.多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型

接下来我们来演示以下多态参数的使用:

父类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

/**

 * 多态参数 - 父类

 */

public class Employee {

    private String name;

    private double sal;

    public Employee(String name, double sal) {

        this.name = name;

        this.sal = sal;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public double getSal() {

        return sal;

    }

    public void setSal(double sal) {

        this.sal = sal;

    }

    // 得到年工资的方法

    public double getAnnual() {

        return 12 * sal;

    }

}

员工子类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

 * 多态参数 - 子类员工

 */

public class Worker extends Employee{

    public Worker(String name, double sal) {

        super(name, sal);

    }

    public void work() {

        System.out.println("普通员工:" + getName() + "正在工作!");

    }

    public double getAnnual() {

        return super.getAnnual();

    }

}

经理子类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

/**

 * 多态参数 - 经理子类

 */

public class Manager extends Employee{

    private double bonus; // 奖金

    public Manager(String name, double sal, double bonus) {

        super(name, sal);

        this.bonus = bonus;

    }

    public double getBonus() {

        return bonus;

    }

    public void setBonus(double bonus) {

        this.bonus = bonus;

    }

    public void manage() {

        System.out.println("经理:" + getName() + "正在管理!");

    }

    @Override

    public double getAnnual() {

        return super.getAnnual() + bonus;

    }

}

我们来测试一下,求不同岗位的雇员的年薪:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

 * 多态参数测试类

 */

public class Test {

    public static void main(String[] args) {

        Worker zhang = new Worker("张工",1000);

        Manager milan = new Manager("milan", 5000, 2000);

        Test test = new Test();

        test.showEmpAnnual(zhang);

        test.showEmpAnnual(milan);

    }

    // 获取员工的年薪,采用多态参数

    public void showEmpAnnual(Employee e) {

        System.out.println(e.getAnnual());

    }

}

输出:

12000.0
62000.0

5.多态参数的高阶用法

我们来对上面的多态参数代码做一个完善,如果传入的是员工,则调用自己的work方法,如果传入的是经理,则调用自己的manage方法

增加一个下面的方法:

?

1

2

3

4

5

6

7

public void testWork(Employee e) {

    if (e instanceof Worker) {

        ((Worker) e).work(); // 向下转型

    } else if (e instanceof Manager) {

        ((Manager) e).manage();

    }

}

测试:

?

1

2

test.testWork(zhang);

test.testWork(milan);

输出:

普通员工:张工正在工作!
经理:milan正在管理!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720107.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习24:《数据准备和特征工程-II》收集数据

构建数据集常用的步骤如下所示&#xff1a; 收集原始数据。识别特征和标签来源。选择抽样策略。拆分数据。 这些步骤在很大程度上取决于你如何构建 ML 问题。本文主要介绍——数据收集-Collecting Data。 目录 1. 数据集的大小和质量 1.1 数据集的大小 1.2 数据集的质量 …

.NET Core webapi 从零开始在IIS上面发布后端接口

文章目录 原因环境配置windows环境.NET Core安装开发端安装服务端安装 新建ASP.NET项目 原因 .NET core是以后.NET未来的趋势&#xff0c;虽然我感觉Java在web后端的主导地位10年内不会动摇&#xff0c;因为Java占据了先发优势。 不过C#的特点就是&#xff0c;简单&#xff0…

mysql三大日志之我对Binlog的理解

mysql 我们先来看一下MySQL的基本架构&#xff0c;从大的方面来讲&#xff0c;一个server层&#xff0c;一个引擎层。server层就像一个接口&#xff0c;可以对接任何符合规定的引擎。具体的细节可以参考我之前写过的文章mysql的这些坑你踩过吗&#xff1f;快来看看怎么优化mys…

Blazor 自定义可重用基础组件之 带标头排序的Table

实现点击标头按所在列值进行排序&#xff0c;是一个非常有用的功能&#xff0c;其他的UI一般搞得非常复杂&#xff0c;添加标志图标什么的&#xff0c;使得本就不宽裕的表格更加拥挤。我的思路是&#xff0c;点击所在列的标头部位&#xff0c;传递标头值&#xff0c;然后根据标…

裸机搭建k8s报错记录

安装教程参考 修复一、 cd /etc/kubernetes/manifests vim kube-scheduler.yaml注释掉 重启 systemctl restart kubelet.service问题二、 https://github.com/kubernetes/kubernetes/issues/70202 一直处于创建中状态 网络原因 cat << EOF > /run/flannel/subnet.…

golang 结构体struct转map实践

1、反射 type sign struct { Name string json:"name,omitempty" Age int json:"age,omitempty" } var s sign s.Name "csdn" s.Age 18 //方式1 反射 var data make(map[string]interface{}) t : reflect.TypeOf(s) v : …

第五步:STM32F4端口复用

什么是端口复用&#xff1f; STM32有很多的内置外设&#xff0c;这些外设的外部引脚都是与GPIO复用的。也就是说&#xff0c;一个GPIO如果可以复用为内置外设的功能引脚&#xff0c;那么当这个GPIO作为内置外设使用的时候&#xff0c;就叫做复用。 例如串口 1 的发送接收引脚…

【C++11】移动语义,完美转发

1.移动语义 1.为什么要有移动语义&#xff1f; C中有拷贝构造函数和拷贝复制运算符&#xff0c;但是这需要占用一定的空间 class MyClass { public:MyClass(const std::string& s): str{ s }{};MyClass(const MyClass& m){strm.str;}private:std::string str; };int …

NSS [NSSRound#7 Team]ec_RCE

NSS [NSSRound#7 Team]ec_RCE 源码如下&#xff1a; <?PHPif(!isset($_POST["action"]) && !isset($_POST["data"]))show_source(__FILE__);putenv(LANGzh_TW.utf8); $action $_POST["action"];$data "".$_POST["…

代理IP,如何助力大数据时代

代理IP&#xff0c;如何为大数据助力 华科云商助力大数据 近年来&#xff0c;我国互联网商业保持持续发展的状态。大环境的优化&#xff0c;各项相关政策的出台&#xff0c;也为互联网经济的发展&#xff0c;提供了强有力的支持。大大小小的企业都想乘风起势&#xff0c;大展宏…

Django核心

安装django pip install django # pip install django3.1.6创建django项目 在一个项目中可以包含多个应用程序。 django-admin startapp app_name #创建一个应用程序 django-admin startproject project_name #创建一个项目运行django项目 python manage.py runserver 80…

REST风格讲解

1.REST风格简介 优点&#xff1a;隐藏资源访问的行为&#xff0c;无法通过地址得知对资源的操作&#xff0c;并且简化了书写 rest风格大概将请求方式分成了Get Post Put Delete四种操作方法。上述行为是约定的方式并不是规范。 RequestMapping注解里面value值存储访问的路…

Docker 中的 .NET 异常了怎么抓 Dump (转载)

一、背景 1. 讲故事 有很多朋友跟我说&#xff0c;在 Windows 上看过你文章知道了怎么抓 Crash, CPU爆高&#xff0c;内存暴涨 等各种Dump&#xff0c;为什么你没有写在 Docker 中如何抓的相关文章呢&#xff1f;瞧不上吗&#xff1f; 哈哈&#xff0c;在DUMP的分析旅程中&a…

【前端学JAVA】基础语法

作为一个前端程序员&#xff0c;其发展前途是远不及后端程序员的。因此&#xff0c;只有了解后端&#xff0c;才能让自己更加具备核心竞争力。本系列教程将以一个前端程序员的角度快速学习JAVA。 新建项目 开发JAVA程序&#xff0c;我们第一步是使用IDEA新建一个项目&#xf…

紫光展锐携手中国联通共建数字世界

6月28日&#xff0c;2023上海世界移动大会&#xff08;MWC上海&#xff09;首日&#xff0c;联通华盛总经理李立新、联通华盛副总经理陈丰伟一行莅临紫光展锐展台参观&#xff0c;紫光集团高级副总裁、紫光展锐CEO任奇伟博士&#xff0c;紫光展锐执行副总裁、工业电子事业部总经…

如何提高OAK相机在树莓派和JETSON上的运行帧率?

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手君。 最…

Lim接口测试平台-接口测试功能详解

一、接口测试 项目地址&#xff1a;Gitee/Github 接口测试模块是整个Lim平台的核心&#xff0c;左侧是接口的模块树&#xff0c;右侧顶部是用例操作功能区&#xff0c;列表展示接口用例信息&#xff1a; 文章目录 一、接口测试 二、维护接口用例 各步骤类型详解 1&#x…

picard的安装

最近在通过GATK所介绍的best practice流程来call SNP流程 1.流程 1.1 BWA比对&#xff0c;获得sam文件 1.2 准备用picard来压缩排序sam文件为bam文件&#xff0c;并对bam文件进行去重复&#xff08;duplicates marking&#xff09; 这是就需要用到picard软件 按照教程网页上…

Mac使用Puppeteer,并启动chromium

Mac使用Puppeteer&#xff0c;并启动chromium Puppeteer官网 chromium下载地址 通过chrome://version 可查询 Chromium 浏览器信息 const puppeteer require(puppeteer);(async () > {const browser await puppeteer.launch({executablePath: 上图可执行文件路径,headl…

爬取12306上所有城市的站台信息

0. 需求 爬取所有城市下的站台信息保存到Excel中: 效果: 1. 定位数据源 在12306随便一个车票查询页面上,通过F12控制台获取网站请求车站数据的URL 博主当前获取的URL为: https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version1.9270*注意…