美文网首页
Java多态知识点总结

Java多态知识点总结

作者: cornprincess | 来源:发表于2020-04-20 22:19 被阅读0次

多态

概述

我们继续使用继承中的的示例代码

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n4" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">public class Employee {
private String name;
private double salary;
private LocalDate hireDay;

public Employee(String name, double salary, int year, int month, int day) {
this.name = name;
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
}

public String getName() {
return name;
}

public double getSalary() {
return salary;
}

public LocalDate getHireDay() {
return hireDay;
}

public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}

@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", salary=" + salary +
", hireDay=" + hireDay +
'}';
}
}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n5" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">public class Manager extends Employee {
private double bonus;

public Manager(String name, double salary, int year, int month, int day) {
// Manager 类的构造器不能访问 Employee 类的私有域,所以必须利用 Employee 类的构造器对这部分私有域进行初始化, 且使用 super 调用构造器的语句必须是子类构造器的第一条语句。
super(name, salary, year, month, day);
this.bonus = 0;
}

public void setBonus(double bonus) {
this.bonus = bonus;
}

public double getSalary() {
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n7" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">public class ManagerTest {
public static void main(String[] args) {
Manager boss = new Manager("Jack", 8000, 2020, 4, 12);
boss.setBonus(2000);

Employee employee1 = boss;
Employee employee2 = new Employee("Alice", 2000, 2020, 4, 2);

System.out.println(employee1.getSalary());
System.out.println(employee2.getSalary());
}
}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n8" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">// output
// 10000.0
// 2000.0</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n13" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">Employee e;
e = new Employee();
e = new Manager();</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n16" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">Employee e = new Employee();
Manager m = e; // error</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n33" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">// method table
Employee:
getName() -> Employee.getName()
getSalary() -> Employee.getSalary()
getHireDay() -> Employee.getHireDay()
raiseSalary() -> Employee.raiseSalary()

Manager:
getName() -> Employee.getName()
getSalary() -> Manager.getSalary()
getHireDay() -> Employee.getHireDay()
raiseSalary() -> Employee.raiseSalary()
setBonus() -> Manager.setBonus()</pre>

1.Java核心技术·卷 I(原书第10版)

Reference

  • 方法签名:方法名和参数列表,(f(int) 和f(String) :方法签名不同,但方法名相同)如果在子类中定义了和超类中签名相同的方法,此时会出现方法重写,但是在方法重写时一定要保证返回类型的兼容性,即允许子类将重写方法的返回类型定义为原返回类型的子类型。

  • 方法重写时子类方法不能低于超类方法的可见性。

注意:

  • 编译器获取方法签名 getSalary()

  • 由于该方法不是 private, static, final 或构造器方法,因此会采用动态绑定,虚拟机在运行时提取方法表

  • 虚拟机搜索 定义了 getSalary 签名的类,此时虚拟机已经知道调用哪个方法。

  • 虚拟机调用方法。

了解规则之后,我们可以看一下测试代码中 employee1.getSalary()的调用过程:

  • 编译器获取所有可能被调用的候选方法:编译器查看对象的声明类型(C)和方法名(f),此过程编译器会一一列举所有 C 类中名为 f 的方法和超类中访问属性为public 且名为 f 的方法。

  • 编译器获取需要调用的方法名字和参数类型:编译器会查看调用方法时提供的参数类型, 如果在所有名为 f 的方法中存在一个与提供的参数类型完全匹配,就选择这个方法,这个过程被称为重载解析(overloading resolution)。由于允许类型转换(int 可以转换为 double, Manager 可以转换为 Employee等),此过程会很复杂,如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后存在多个方法与之匹配,就会报告一个错误。

  • 静态绑定(static bingding):如果方法为 private, static, final修饰的方法,或者是构造器方法,那么编译器可以准确地知道应该调用哪个方法。

  • 动态绑定(dynamic binding):不是静态绑定的方法都将采取动态绑定,调用的方法依赖与隐式参数的实际类型,在运行时实现动态绑定,此时虚拟久会调用与 x 所引用对象的实际类型最合适的那个类的方法:即假设 x 的实际类型为 D, D 为 C 的子类,且在 D 类中存在方法签名相同的方法,此时就会调用 D 中的方法,否则在 D 的超类中寻找该方法。

    • 由于每次调用方法都有进行搜索,时间开销很大,因此,虚拟机预先为每个类常见了一个方法表(method table),其中列出了所有方法的签名和实际调用的方法,这样,在真正调用方法的时候,虚拟机仅查找这个表就行了。

我们假设现在调用 x.f(args) 隐式参数 x 声明为类 C 的一个对象,下面是调用过程的详细描述:

方法调用的过程

因为不是每个雇员(Employee)都是经理(Manager),不是 is-a 的关系,在代码层面也很好理解,如果这样赋值,很容易造成 m 调用 Manager 专属的方法引起错误。

但是需要主要注意不能将超类的引用复制给子类变量,如

在 Java 程序设计语言中,对象变量是多态的,一个 Employee 变量既可以引用一个 Employee 对象,也可以引用一个 Employee 类的任何一个子类的对象。

有一个用来判断是否应该设计为继承关系的简单规则,这就是 ”is-a“ 规则,它表明子类的每个对象也是超类的对象,例如上面的例子:每个 管理者(Manager)是雇员(Employee)。is-a 规则的另一种表述法是置换法则,它表明程序中出现超类对象的任何地方都可以用子类对象置换,如。

像上述情形,一个对象变量可以只是多种实际类型的现象称为多态(polymorphism),在运行时能够 自动地选择调用哪个方法的现象称为动态绑定(dynamic binding)。

在上述测试代码中,我们可以看到声明为 Employee 的变量既可以引用 Employee 类型的对象,也可以引用 Manager 类型的对象,当引用 Employee 对象时调用其 getSalary方法, 当引用 Manager 对象时调用 Manager 对象的方法。

测试代码:

相关文章

  • Java多态知识点总结

    多态 概述 我们继续使用继承中的的示例代码 public class Employee {private Stri...

  • 多态

    多态的总结,把几个知识点一起总结了: 1.继承 2.接口 3.重写 4.多态 5.一些相关知识点 可能不够全面仔细...

  • 面经一

    目的: 总结下面试时遇到的问题,并附上自己的答案. 1 Java基础 1.1 Java的继承,多态。 以及多态...

  • 重识Java多态

    今天面试被问到了Java多态的知识点 面试官: 了解多态吗,说一说你对多态的理解我:balabala..面试官:知...

  • 安卓技能储备

    没有写完所有的知识点,只是面试中会问到的一些知识点 Java基础 java语言的特性:封装,继承,多态面向对象的五...

  • java编程思想(一)---笔记

    《java编程思想》这本书被视为java经典,再此总结一些重点知识: 1.java多态性理解 所谓多态就是指程序中...

  • java多态总结

    Java多态 1、多态的总结 面向对象编程有三大特性:封装、继承、多态。 封装隐藏了类的内部实现机制,可以在不影响...

  • Java多态总结

    概念介绍 定义多态,是面向对象的程序设计语言最核心的特征。多态,意味着一个对象有着多重特征,可以在特定的情况下,表...

  • Java多态总结

    写在前面 由于找工作的原因,最近几个月都没有更新博客了。。。这篇可能是今年最后一篇总结类的博文了,希望能够写的好点...

  • java多态面试题

    java多态性 多态分两种: (1) 编译时多态(设计时多态):方法重载。 (2) 运行时多态:JAVA运...

网友评论

      本文标题:Java多态知识点总结

      本文链接:https://www.haomeiwen.com/subject/jnvsihtx.html