欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-17 08:13:58
...

理解误区

学习的第一门语言就是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()方法。 ——动态绑定

图示

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

前提

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

执行:

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