Java中的多态、方法重载与方法重写

Java中的多态、方法重载与方法重写。

一、多态

1.1 了解多态之前先简单了解 “绑定”

1.1.1 绑定的概念

子类重写父类方法(实现类实现接口方法)的情况下,程序调用的方法到底是调用了父类(接口)中的方法,还是调用了子类(实现类)中的方法呢?我们将确定这种调用哪个方法的操作叫做绑定。

绑定又分为静态绑定和动态绑定,又叫前期绑定和后期绑定。

1.1.2 静态绑定(前期绑定)
  • 静态绑定就是在程序运行前就已经绑定了,即在程序编译的过程中就知道要调用的这个方法是哪个类中定义的方法了。
  • java中只有private, static, final修饰的方法以及构造方法静态绑定的.
    • private 方法的特点是只能在本类中使用,即不能被继承。
      一个方法不能被继承,那么父类对象的引用调用该方法的时候,必然是调用了父类对象中的方法。
    • static 方法又叫类方法,static修饰的成员方法能被继承,但是不能被子类覆盖,但是可以被子类 “隐藏”。static修饰的方法不依赖对象而存在,某个类的对象的引用调用了一个static方法,必定调用的是该类中的方法。
      不推荐使用对象调用静态方法。关于 “隐藏” 的概念后面会进行说明。
    • final 方法能被继承,但是不能被子类覆盖。
      某类中的方法不能被重写,该类的对象的引用调用这个方法,必定是调用了该类的对象中的方法。
    • 构造方法 不能被继承,不能被子类覆盖。
      一个类中怎么可能存在不同方法名的构造方法呢。
  • 小结: 如果一个方法不能被继承, 或者继承后不能被重写(覆盖), 那么这个方法就采用静态绑定.
1.1.3 动态绑定(后期绑定)
  • 在程序运行时才能确定调用的是哪个类中的方法。
1.1.4 小结
  • 关于动态绑定的原理有些复杂,我们暂时不需要知道,因为这节的标题是 “了解” 绑定嘛。
  • 我们需要知道的是: 什么是静态绑定,什么是动态绑定,绑定和Java多态有什么关系。 如下:
    • 子类重写父类方法(实现类实现接口方法)的情况下,程序调用的方法到底是调用了父类(接口)中的方法,还是调用了子类(实现类)中的方法呢?我们将确定这种调用哪个方法的操作叫绑定。
    • 静态绑定就是在程序运行前就已经绑定了,即在程序编译的过程中就知道要调用的这个方法是哪个类中定义的方法了。
    • 动态绑定就是在程序运行时才进行绑定,即在程序运行的时才能知道要调用的这个方法是哪个类中定义的方法。
    • Java的多态就是动态绑定机制。

1.2 多态的概念

  • 同一操作作用于不同的对象,将会产生不同的结果。
  • 多态在java中最基本的体现就是:
    • 父类引用变量指向父类对象,调用方法A,调用的是父类中定义的A方法;
      父类引用变量指向子类对象,调用重载的方法A,调用的是子类中定义的A方法;
  • 按照上述两点理解,多态应该是一种运行期的状态,或者说是动态绑定。

1.3 多态的前提

  1. 有类的继承或接口的实现;
  2. 子类要重写父类的成员方法;
  3. 父类引用指向子类对象(向上转型);

1.4 动态多态和静态多态

  • 动态绑定被认为是动态多态, 因为只有在运行期才能知道调用的是哪个类中定义的方法;
  • 一般认为java中的方法重载是静态多态, 因为它需要在编译期决定具体调用哪个方法.
    我更倾向于方法重载和多态是没有关系的;

1.5 注意

  • 只有非private的静态变量, 成员变量, 静态方法, 成员方法能被继承;
    代码块, 构造函数不能被继承;
    代码块应该关注的是执行顺序(静态代码块,构造代码块,构造函数,main函数之间的执行顺序);
  • 父类中非private的成员变量, 静态变量, 静态方法, final变量, final方法能被继承不能被重写, 父类中只有非private并且非final的成员方法能被重写.
    子父类中有同名静态变量同名成员变量同签名静态方法时, 父类中的这三种成分会被子类"隐藏";
    "父类的变量被子类隐藏"可以理解为使用子类引用不能调用父类的该变量;
  • 向上转型: 父类引用指向子类对象 ( Super father = new Sub(); )
    向下转型: 子类引用指向子类对象 ( Sub sub1 = (Sub) father; 或 Super father = new Sub(); )
  • “编译看左边, 运行看右边”, 右边没有, 就向上查找调用父类的;

1.6 关于"隐藏"

  • 下面是Java文档中对隐藏域的描述:

Within a class, a field that has the same name as a field in the superclass hides the superclass’s field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super. Generally speaking, we don’t recommend hiding fields as it makes code difficult to read.

  • 翻译成中文:
    在一个类中, 如果子父类中有同名的成员变量, 那么即使他们类型不同, 只要名字一样, 父类中的成员变量就会被隐藏; 在子类中,父类的成员变量不能被简单的用引用来访问。而是,必须从父类的引用获得父类被隐藏的成员变量,一般来说,我们不推荐隐藏成员变量,因为这样会使代码变得难以阅读。
  • 简单来说, 就是子类不能去重写覆盖父类的成员变量, 所以成员变量的访问不能像成员方法一样使用多态去访问. 这个特性同样适用于子父类中的同名静态变量和同签名静态方法;
    例如在多态环境下( Super s = new Sub(); )
  • 不推荐使用隐藏(不推荐子父类中声明同名静态变量或同名成员变量或同签名静态方法);
    不推荐使用引用调用静态方法;

二、方法重载与方法重写

2.1 重载和重写的概念

  • 方法重载(Overload)
    • 发生在同一个类中. 方法名必须相同, 方法的参数列表必须不同(类型, 个数, 顺序其中一个或多个条件不同), 返回值可以不同, 权限修饰符可以不同, 异常声明可以不同.
  • 方法重写/覆盖(Override)
    • 发生在子父类中. 方法名和参数列表必须相同, 返回值小于等于父类, 权限修饰符小于等于父类, 异常声明小于等于父类(小到可以不抛出异常).
      只有成员方法能被重写.
      子类不能重写父类中被final修饰的成员方法.
      子类不能重写父类中被private修饰的成员方法.

2.2 注意

  • 重载是编译期概念, 重写(覆盖)是运行期间的概念.
  • 重载遵循所谓“编译期绑定”,即在编译时根据参数变量的类型判断应该调用哪个方法.
    重写遵循所谓“运行期绑定”,即在运行的时候,根据引用变量所指向的实际对象的类型来调用方法.
  • 我们上面说过多态是一种运行期状态,是动态绑定;
    但是重载是在编译期间就已经确定要调用哪个方法了, 所以重载不是多态, 重写才是多态;
    重载只是一种语言特性, 是一种语法规则, 与多态无关, 与面向对象也无关;
    但是很多人说重载是编译时多态, 即静态多态. 在Java中提到多态, 在不特别说明的情况下都是指动态多态;
  • 只有非private的成员方法能被重写. 成员变量不会被重写, 但是父类中的成员变量会被子类"隐藏";

欢迎批评指正.

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值