Java三大特性的最后一个分水岭——多态性


大家好,我是卷心菜,可以叫我菜菜(名副其实了属于是,哈哈~),大二学生一枚。本篇主要讲解Java面向对象的三大特征之一:多态性,也是最后一个特性。如果您看完文章有所收获,可以三连支持博主哦~,嘻嘻。


一、基本介绍

  • 基本概念:多态性是面向对象中最重要的特征,它是指在父类中定义的方法被子类继承之后,可以具有不同的行为(可以理解为方法体不同),这使得同一个方法在父类及其各个子类中具有不同的行为。
  • Java中的体现:父类的引用指向子类的对象(向上转型),是一个运行时类型。
  • 编译时类型和运行时类型:编译时类型由声明变量时使用的类型决定,运行时类型由实际赋给变量的对象决定。即:编译看左边,运行看右边。而"看左边",看的是父类的引用(父类中不具备子类特有的方法);“看右边”,看的是子类的对象(实际运行的是子类重写父类的方法)。
  • 向上转型:子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象。
    在这里插入图片描述

二、代码举例

写个两个类,用来测试:

class Person {
    
    
   String name;
   int age;
   public void oneFu() {
    
    
       System.out.println("我是父类的方法one");
   }
   public void twoFu() {
    
    
       System.out.println("我是父类的方法two");
   }
}
class Man extends Person {
    
    
    String major;
    char gender;
    @Override
    public void oneFu() {
    
    
        System.out.println("我重写了父类的方法one");
    }
    public void oneZi() {
    
    
        System.out.println("这是我自己的方法");
    } 
}

当我使用idea编译器进行测试时,会出现图片下面的提示:
在这里插入图片描述
接下来我们依次输入这些内容,看看它的运行情况:
在这里插入图片描述
这里的向下转型先不在意,以后会出一篇关于Java向上向下转型的文章,重点是看其它的属性和方法。可以看出,person引用在执行方法oneFu时,本应该是输出我是父类的方法one,但是由于是多态性,实际运行的是子类重写后的方法,输出我重写了父类的方法one,所以说多态是一个运行时类型。


三、虚拟方法调用

  • 什么是虚拟方法调用:有了对象的多态性以后,在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法,这就是虚拟方法调用。
  • 子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

再来举个简单的例子吧:
在这里插入图片描述

四、使用前提

相信通过上面的两道案例,聪明的小伙伴可以猜出多态性的使用前提了:

  • 多态性的使用发生在类的继承关系中
  • 涉及到方法的重写
  • 对象的多态性,只适用于方法,不适用于属性

五、课后练习

写出下列代码的输出结果,看看你写对了没有:

class Person {
    
    
    int count = 10;
    public void display() {
    
    
        System.out.println(this.count);
    }
}
class Man extends Person {
    
    
    int count = 20;
    public void display() {
    
    
        System.out.println(this.count);
    }
}
public class FieldMethodTest {
    
    
    public static void main(String[] args) {
    
    
        Person person = new Man();
        System.out.println(person.count);//10
        person.display();//20
        Person b = person;
        System.out.println(b == person);//true
        System.out.println(b.count);//10
        b.display();//20
    }
}

最终的输出结果是:10,20,true,10,20,你写对了吗?


最后总结一下这个小练习:

  • 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边

  • 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边


感谢阅读,一起进步,嘻嘻~

猜你喜欢

转载自blog.csdn.net/weixin_59654772/article/details/124154900
今日推荐