多态(Polymorphism)

:::tips

概述:

  • 同一对象,在不同时刻表现出来的不同形态
  • 有继承/实现关系
  • 有方法重写
  • 父类引用指向子类(接口引用指向实现类对象)

访问特点:

  • 成员变量:编译看左,运行看左
  • 成员方法:编译看左,运行看右
  • [成员变量跟方法访问不同是因为方法有重写,变量没有]

多态好处:

  • 提高程序的扩展性
  • 定义方法时,使用父类型作为参数,使用时,使用子类型参与操作

多态弊端:

  • 不能使用子类特有功能

#▲对象的多态:

  • 一个对象的编译类型和运行类型可以不一致
  • 编译类型在定义对象时,就确定了,不能改变
  • 运行类型可变
  • 编译看左运行看右
  • [Animal animal = new cat(); animal的编译类型是Animal运行类型是cat]

向上转型:

  • 父类引用指向子类对象
  • 语法:
    • 父类类型 引用名 = new 子类类型();
  • 特点:
    • 编译看左运行看右
    • 可以调用父类的所有成员不能调用子类特有成员

向下转型:

  • 语法:
    • 子类类型 引用名 = (子类类型) 父类引用;
  • 特点
    • 只能强转父类的引用,不能强转父类的对象
    • 要求父类的引用必须指向的是当前目标的类型对象
    • 可以调用子类类型中的所有成员

instanceOf比较操作符:

  • 用于判断对象的[运行]类型是否为xx类型或xx类型的子类型

#▲java的动态绑定机制:

  • 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  • 当调用对象的属性时,没有多态绑定机制,哪里声明哪里使用 :::

    1. public class PolyDetail{
    2. public static void main(String[] args) {
    3. Base base = new Sub();
    4. System.out.println(base.count);//10
    5. Sub sub = new Sub();
    6. System.out.println(sub.count);//20
    7. }
    8. }
    9. class Base {//子类
    10. int count = 10;//属性
    11. }
    12. class Sub extends Base {
    13. int count = 20;
    14. }

    ```java //数组定义类型为父类类型,里面保存的实际元素类型为子类型 public static void main(String[] args) { /*创建一个person对象 两个student跟teacher对象

    1. 统一放在数组中 并调用父类的say()方法*/

    person[] persons = new person[5];//对象数组、 persons[0] = new person(“jack”, 20); persons[1] = new Student(“mary”, 30, 100); persons[2] = new Student(“Mike”, 25, 80); persons[3] = new Teacher(“king”, 50, 30000); persons[4] = new Teacher(“scott”, 48, 20000);

    //循环遍历多态数组,调用say for (int i = 0; i < persons.length ; i++) {

    1. //person[i]编译类型是person 运行类型是根据实际情况由JVM判定
    2. System.out.println(persons[i].say());//动态绑定机制
    3. //调用子类特有方法
    4. if (persons[i] instanceof Student) {//判断persons[i]的运行类型是不是Student
    5. Student student = (Student)persons[i];//向下转型 强转
    6. student.study();
    7. //缩写 ((Student)persons[i]).study;
    8. System.out.println(persons[i]);
    9. } else if (persons[i] instanceof Teacher) {
    10. ((Teacher)persons[i]).teach();
    11. } else if (persons[i] instanceof person) {
    12. } else {
    13. System.out.println("类型有误!");
    14. }

    } } //父类 public class person { private String name; private int age; /*

    1. 无参带参构造方法
    2. setget方法

    */ //返回名字年龄 public String say() {

    1. return "名字: " + name + " 年龄: " + age;

    } }

//教师子类 public class Teacher extends person{ private double salary;

  1. public Teacher(String name, int age, double salary) {
  2. super(name, age);
  3. this.salary = salary;
  4. }
  5. //setget方法
  6. @Override
  7. public String say() {
  8. return "教师: " + super.say() + " salary: " + salary;
  9. }
  10. public void teach() {
  11. System.out.println("教师" + getName() + "正在授课");
  12. }

}

//学生子类 public class Student extends person{ private double score;

  1. public Student(String name, int age, double score) {
  2. super(name, age);
  3. this.score = score;
  4. }
  5. //setget方法
  6. @Override
  7. public String say() {
  8. return "学生: " + super.say() + " score: " + score;
  9. }
  10. public void study() {
  11. System.out.println("学生" + getName() + "正在听讲");
  12. }

}

  1. ```java
  2. //方法定义的形参类型为父类类型,实参类型允许为子类类型
  3. /*
  4. 定义员工类Employee 包含姓名 月工资salary 以及计算年工资getAnnual的方法
  5. 普通员工经理继承员工 经理多了奖金bonus和管理manage方法 员工多了work方法
  6. 普通员工跟经理重写getAnnual方法
  7. 测试类中添加showEmpAnnual(Employee e) 实现获取任何员工对象的年薪
  8. 并在main调用该方法e.getAnnual()
  9. 测试类中添加一个方法 tesWork 如果是普通员工调用work方法
  10. 如果是经理调用manage方法
  11. */
  12. public class PloyParameter {
  13. public static void main(String[] args) {
  14. Worker tom = new Worker("tom", 1000);
  15. Manager milan = new Manager("milan", 5000, 10000);
  16. PloyParameter ployParameter = new PloyParameter();
  17. ployParameter.showEmpAnnual(tom);
  18. ployParameter.showEmpAnnual(milan);
  19. ployParameter.tesrWork(tom);
  20. ployParameter.tesrWork(milan);
  21. }
  22. //调用年薪方法
  23. public void showEmpAnnual(Employee e) {
  24. System.out.println(e.getName() + "的年薪有: " + e.getAnnual());
  25. }
  26. //添加方法 分别调用不同子类方法
  27. public void tesrWork(Employee e) {
  28. if (e instanceof Worker) {
  29. ((Worker) e).work();
  30. } else if (e instanceof Manager) {
  31. ((Manager) e).manage();
  32. } else {
  33. System.out.println("不做处理");
  34. }
  35. }
  36. }
  37. //父类
  38. public class Employee {
  39. private String name;
  40. private double salary;
  41. /*
  42. 无参带参构造方法
  43. setget方法
  44. */
  45. //得到年工资的方法
  46. public double getAnnual() {
  47. return 12 * salary;
  48. }
  49. }
  50. //员工
  51. public class Worker extends Employee {
  52. public Worker(String name, double salary) {
  53. super(name, salary);
  54. }
  55. public void work() {
  56. System.out.println("员工: " + getName() + " is working!");
  57. }
  58. @Override
  59. public double getAnnual() {//普通员工没有奖金 直接调用父类方法
  60. return super.getAnnual();
  61. }
  62. }
  63. //经理
  64. public class Manager extends Employee{
  65. private double bonus;
  66. public Manager(String name, double salary, double bonus) {
  67. super(name, salary);
  68. this.bonus = bonus;
  69. }
  70. //setget方法
  71. public void manage() {
  72. System.out.println("经理: " + getName() + " is manageing!");
  73. }
  74. @Override
  75. public double getAnnual() {
  76. return super.getAnnual() + bonus;
  77. }
  78. }