• Java学习 --- 面向对象之多态


    目录

    一、什么是多态

    二、多态的具体体现

     三、注意事项

    四、动态绑定机制

    五、多态数组

     六、多态参数


    一、什么是多态

    方法或对象具有多种形态,是面向对象的三大特征之一,多态是建立在封装和继承之上的。

    二、多态的具体体现

    1、方法的多态,如方法的重写和重载。

    ①、使用方法重载实现

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. B b = new B();
    4. System.out.println(b.sum(1,2));
    5. System.out.println(b.sum(1,2,3));
    6. }
    7. }
    8. class B {
    9. public int sum(int n1,int n2){
    10. return n1 + n2;
    11. }
    12. public int sum(int n1,int n2,int n3){
    13. return n1 + n2 + n3;
    14. }
    15. }

    上述代码:通过传入参数的个数不一样,调用的方法也不一样,通过重载体现了方法的多态。

    ②、使用方法重写实现

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. B b = new B();
    4. A a = new A();
    5. a.say();
    6. b.say();
    7. }
    8. }
    9. class A{
    10. public void say(){
    11. System.out.println("A类的say方法被调用...");
    12. }
    13. }
    14. class B extends A{
    15. public void say(){
    16. System.out.println("B类的say方法被调用...");
    17. }
    18. }

     从结果就能看出,虽然是同一方法,但根据对象不一样调用结果是不一样的。

    2、对象多态

    1、一个对象的编译类型和运行类型可以不一致。

    2、编译类型在定义对象时,就确定了,不能改变

    3、运行类型是可以变化的。

    4、编译类型看定义时 = 号的左边,运行类型看 = 号的右边。

    1. public class Animal {
    2. public void cry(){
    3. System.out.println("动物种类。。。");
    4. }
    5. }
    1. public class Dog extends Animal {
    2. public void cry() {
    3. System.out.println("小狗是狗类");
    4. }
    5. }
    1. public class Cat extends Animal {
    2. public void cry() {
    3. System.out.println("小猫是猫类");
    4. }
    5. }
    1. public class Test02 {
    2. public static void main(String[] args) {
    3. //animal的编译类型是Animal,运行类型是Dog
    4. Animal animal = new Dog();
    5. animal.cry();//因为animal的运行类型是Dog,所以会去调用Dog类的cry方法。
    6. animal = new Cat(); //因为animal的运行类型发生改变,所以会调用Cat里的cry方法
    7. animal.cry();
    8. }
    9. }

    运行结果:

     三、注意事项

    多态的前提是:两个对象(类)存在继承关系

    多态向上转型

    ①、本质上,父类的引用指向了子类对象。

    ②、在语法上:父类类型  引用名 = new 子类类型();

    ③、编译类型看左边,运行类型看右边,可以调用父类中的所有成员,但必须遵守访问权限,不能调用子类中特有成员,最终运行效果看子类的具体实现。

     多态向下转型

    ①、在语法上:子类类型 引用名 = (子类类型)父类引用

    ②、只能强转父类引用,不能强转父类对象

    ③、要求父类的引用必须指向的是当前目标类型的对象

    ④、当向下转型后,可以调用子类类型中所有的成员

    1. public class Cat extends Animal {
    2. public void cry() {
    3. System.out.println("小猫是猫类");
    4. }
    5. public void eat(){
    6. System.out.println("小猫吃东西");
    7. }
    8. }
    1. public class Test02 {
    2. public static void main(String[] args) {
    3. Animal animal = new Cat();
    4. //向下转型
    5. Cat cat = (Cat) animal;
    6. //调用子类的特有方法
    7. cat.eat();
    8. }
    9. }

     属性没有重写,属性的值看编译类型

    1. public class Test03 {
    2. public static void main(String[] args) {
    3. //这里的base编译类型是Base
    4. Base base = new Sub();
    5. System.out.println(base.count);//根据base的编译类型这里的值为1
    6. Sub sub = new Sub();
    7. System.out.println(sub.count);//2
    8. }
    9. }
    10. class Base{
    11. int count = 1;
    12. }
    13. class Sub extends Base{
    14. int count = 2;
    15. }

    instanceOf比较操作符,用于判断对象的运行类型是否为某个类型或某个类型的子类型

    1. public class Test04 {
    2. public static void main(String[] args) {
    3. D d = new D();
    4. System.out.println(d instanceof D);//true
    5. System.out.println(d instanceof C);//true
    6. //当编译类型为C时,运行类型为D时
    7. C c = new D();
    8. System.out.println(c instanceof D);//true
    9. System.out.println(c instanceof C);//true
    10. }
    11. }
    12. class C{ }
    13. class D extends C{
    14. }

    四、动态绑定机制

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

    2、当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. A a = new B();
    4. System.out.println(a.sum());//40 -> 30
    5. System.out.println(a.sum1());//30 -> 20
    6. }
    7. }
    8. class A{
    9. public int i = 10;
    10. //这里Java会调用动态绑定机制
    11. public int sum(){
    12. return getI() + 10;
    13. }
    14. public int sum1(){
    15. return i + 10;
    16. }
    17. public int getI(){
    18. return i;
    19. }
    20. }
    21. class B extends A{
    22. public int i = 20;
    23. // public int sum(){
    24. // return i + 20;
    25. // }
    26. public int getI(){
    27. return i;
    28. }
    29. // public int sum1(){
    30. // return i + 10;
    31. // }
    32. }

    五、多态数组

    数组的定义类型为父类类型,里面保存的实际元素类型为子类型。

    Person类

    1. public class Person {
    2. private String name;
    3. private int age;
    4. public Person(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. public int getAge() {
    15. return age;
    16. }
    17. public void setAge(int age) {
    18. this.age = age;
    19. }
    20. //返回信息
    21. public String say(){
    22. return "姓名:" + name + "\t年龄" + age;
    23. }
    24. }

    Student 类 

    1. public class Student extends Person{
    2. private double score;
    3. public Student(String name, int age, double score) {
    4. super(name, age);
    5. this.score = score;
    6. }
    7. public double getScore() {
    8. return score;
    9. }
    10. public void setScore(double score) {
    11. this.score = score;
    12. }
    13. //重写父类方法
    14. @Override
    15. public String say() {
    16. return super.say() + "\t成绩:" + score;
    17. }
    18. }

    Teacher类 

    1. public class Teacher extends Person {
    2. private double salary;
    3. public Teacher(String name, int age, double salary) {
    4. super(name, age);
    5. this.salary = salary;
    6. }
    7. public double getSalary() {
    8. return salary;
    9. }
    10. public void setSalary(double salary) {
    11. this.salary = salary;
    12. }
    13. @Override
    14. public String say() {
    15. return super.say() + "\t工资" + salary;
    16. }
    17. }

     PloyArray类

    1. public class PloyArray {
    2. public static void main(String[] args) {
    3. Person[] people = new Person[5];
    4. people[0] = new Person("tom",20);
    5. people[1] = new Student("小明",13,90);
    6. people[2] = new Student("小红",14,80);
    7. people[3] = new Teacher("老李",12,9200);
    8. people[4] = new Student("小美",15,91);
    9. //循环遍历
    10. for (int i = 0; i
    11. //这里使用了Java的动态绑定机制,
    12. //people[i]的编译类型是Person,而调用say方法时的运行状态由JVM决定
    13. System.out.println(people[i].say());
    14. }
    15. }
    16. }

    运行结果:

     

    在多态数组中调用子类特有的方法:

    在Teacher类 新增特有的方法

    1. //子类特有方法
    2. public void teach(){
    3. System.out.println("老师" + getName() + "正在讲课。。。");
    4. }

     PloyArray类

    1. public class PloyArray {
    2. public static void main(String[] args) {
    3. Person[] people = new Person[5];
    4. people[0] = new Person("tom",20);
    5. people[1] = new Student("小明",13,90);
    6. people[2] = new Student("小红",14,80);
    7. people[3] = new Teacher("老李",12,9200);
    8. people[4] = new Student("小美",15,91);
    9. //循环遍历
    10. for (int i = 0; i
    11. //这里使用了Java的动态绑定机制,
    12. //people[i]的编译类型是Person,而调用say方法时的运行状态由JVM决定
    13. System.out.println(people[i].say());
    14. //使用instanceof判断people[i]的运行类型
    15. if (people[i] instanceof Teacher){
    16. //调用子类特有方法
    17. ((Teacher)people[i]).teach();
    18. }
    19. }
    20. }
    21. }

    运行结果:

     六、多态参数

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

    Employee类

    1. public class Employee {
    2. private String name;
    3. private double salary;
    4. public Employee(String name, double salary) {
    5. this.name = name;
    6. this.salary = salary;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. public double getSalary() {
    15. return salary;
    16. }
    17. public void setSalary(double salary) {
    18. this.salary = salary;
    19. }
    20. //计算年薪
    21. public double getAnnual(){
    22. return 12 * salary;
    23. }
    24. }

    Worker类 

    1. public class Worker extends Employee{
    2. public Worker(String name, double salary) {
    3. super(name, salary);
    4. }
    5. public void work(){
    6. System.out.println("普通员工" + getName() + "在工作");
    7. }
    8. @Override
    9. public double getAnnual() {
    10. return super.getAnnual();
    11. }
    12. }

     Manager类

    1. public class Manager extends Employee {
    2. private double bonus;
    3. public Manager(String name, double salary, double bonus) {
    4. super(name, salary);
    5. this.bonus = bonus;
    6. }
    7. public double getBonus() {
    8. return bonus;
    9. }
    10. public void setBonus(double bonus) {
    11. this.bonus = bonus;
    12. }
    13. public void manage(){
    14. System.out.println("经理" + getName() + "在管理");
    15. }
    16. @Override
    17. public double getAnnual() {
    18. return super.getAnnual() + bonus;
    19. }
    20. }
    1. public class Test01 {
    2. public static void main(String[] args) {
    3. Worker worker = new Worker("小李", 6000);
    4. Manager manager = new Manager("老张", 10000, 5000);
    5. Test01 test01 = new Test01();
    6. test01.getAndAnnual(manager);
    7. test01.getWork(worker);
    8. }
    9. //根据对象获取年工资
    10. public void getAndAnnual(Employee e){
    11. //使用动态绑定机制
    12. System.out.println(e.getAnnual());
    13. }
    14. public void getWork(Employee e){
    15. //判断对象类型
    16. if (e instanceof Worker){
    17. ((Worker)e).work();//向下转型
    18. }else {
    19. ((Manager)e).manage();
    20. }
    21. }
    22. }

  • 相关阅读:
    mybatis-plus的多数据源sql拦截&动态表名
    程序化交易(一)交易接口接入
    房屋租赁管理系统的设计与实现
    工业智能网关BL110应用之三十八: COM口如何配置采集Modbus协议设备
    数据库MYSQL
    VoLTE端到端业务详解 | VoLTE基本概念
    Linux简单命令学习 -- useradd passwd userdel
    磁盘空间不够引发的控制录像程序崩溃到后端的解决方式
    西北主要河流水系(绿洲)流域(山区)及高程分类数据集(一)
    0基础转行软件测试,如何实现月薪9.5k+
  • 原文地址:https://blog.csdn.net/qq_46093575/article/details/126807020