Java理解误区——方法的重载是多态性的一种体现?

理解误区

学习的第一门语言就是Java了,还记得在初学Java的时候,还是遇到了很多的困难,很多的知识点还不能理解。提到Java的面向对象,相信很多人都会印象深刻吧,但是对于初学者来说,理解起来确实还是有些难度的。

还记得当时很不理解面向对象的多态性,就去问了问学姐,得到的答案是,暂时可以理解,方法的重载是多态性的一种体现,至于更深层次的理解,可以随着时间以后慢慢理解。

方法的重载是多态性的一种体现吗? 其实这是一个误区,让我很长的一段时间都理解错了,直到又一次系统复习Java的时候才理解,方法的重载并不是是多态性的一种体现

下面具体谈谈方法的重载和多态性。

方法的重载

重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

特点

与返回值类型无关,只看参数列表,且参数列表必须不同。 (参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。

"两同一不同":

  • 同一个类、相同方法名

  • 参数列表不同:参数个数不同,参数类型不同

注:判断是否为重载,跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!

示例

//返回两个整数的和
int add(int x,int y){return x+y;}

//返回三个整数的和
int add(int x,int y,int z){return x+y+z;}

//返回两个小数的和
double add(double x,double y){return x+y;}

方法的重载、重写与多态性(方法的重载是多态性的一种体现?NO)*

从编译和运行的角度看:
重载,是指允许存在多个同名方法,而这些方法的参数不同。 编译器根据方法不同的参数表, 对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。 它们的调用地址在编译期就绑定了。 Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法

所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定” ;

对于多态,只有等到方法调用的那一刻, 解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”
引用一句Bruce Eckel的话: “不要犯傻,如果它不是晚绑定, 它就不是多态。

所以说,方法的重载并不是多态性的一种体现

下面来看看多态性

多态性

如何理解多态性?

可以理解为一个事物的多种形态。

何为多态性?

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

  • 可以直接应用在抽象类和接口上

多态性的作用

提高了代码的通用性,常称作接口重用

多态性的使用

虚拟方法调用

有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

总结:编译,看左边;运行,看右边。

多态性的注意事项

Java引用变量有两个类型: 编译时类型和运行时类型。 编译时类型由声明该变量时使用的类型决定, 运行时类型由实际赋给该变量的对象决定。 简称: 编译时, 看左边;运行时, 看右边。

  • 若编译时类型和运行时类型不一致, 就出现了对象的多态性(Polymorphism)

  • 多态情况下, “看左边” : 看的是父类的引用(父类中不具备子类特有的方法);“看右边” : 看的是子类的对象(实际运行的是子类重写父类的方法)

  • 对象的多态 —在Java中,子类的对象可以替代父类的对象使用

    • 一个变量只能有一种确定的数据类型

    • 一个引用类型变量可能指向(引用)多种不同类型的对象

      Person p = new Student();
      Object o = new Person();//Object类型的变量o, 指向Person类型的对象
      o = new Student(); //Object类型的变量o, 指向Student类型的对象
      
  • 子类可看做是特殊的父类, 所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。

  • 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

    Student m = new Student();
    m.school = “pku”; //合法,Student类有school成员变量
    Person e = new Student();
    e.school = “pku”; //非法,Person类没有school成员变量
    

    属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

  • 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

多态性的使用前提

① 类的继承或者实现关系 ② 方法的重写 ③向上转型

多态性示例

方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法

public class Test {
    public void method(Person e) {
        // ……
        e.getInfo();
    }
    public static void main(Stirng args[]) {
        Test t = new Test();
        Student m = new Student();
        t.method(m); // 子类的对象m传送给父类类型的参数e
    }
}

虚拟方法调用(Virtual Method Invocation)

正常的方法调用

Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();

虚拟方法调用(多态情况下)

子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法

编译时类型和运行时类型

编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。 ——动态绑定

图示

image-20200601084747489

前提

Person类中定义了welcome()方法,各个子类重写了welcome()。

执行:

多态的情况下,调用对象的welcome()方法,实际执行的是子类重写的方法。


版权声明:本文为qq_42937522原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。