多态

本文最后更新于 2 分钟前,文中所描述的信息可能已发生改变。

多态

Polymorphism

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。

编译时多态(静态多态)

Compile-time Polymorphism (Static Polymorphism)

编译时多态,也称为静态多态,通过方法重载(Overloading)实现。编译时多态在编译阶段决定调用哪一个方法。

运行时多态(动态多态)

Run-time Polymorphism (Dynamic Polymorphism)

运行时多态,也称为动态多态,通过方法重写(Overriding)实现。运行时多态在运行阶段决定调用哪一个方法,依赖于对象的实际类型。

方法重写

Overriding

在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为重写。 子类重写父类的非静态方法,替代父类的方法实现,运行时基于实际对象类型调用方法(动态绑定)。

访问权限

Access Modifiers

子类方法的访问权限比父类方法的访问权限更宽松。

返回类型

Return Type

子类方法的返回类型必须与父类方法的返回类型相同。

子类方法的返回类型可以是父类方法返回类型的子类型。换而言之,子类方法的返回值比父类方法的返回值更具体。

tip提示

Java5 引入了协变返回类型,允许子类重写父类方法时返回一个子类类型。

java
class Animal {
    public Animal getAnimal() {
        System.out.println("This is an animal!");
        return new Animal();
    }
}

class Dog extends Animal {
    @Override
    public Dog getAnimal() {
        System.out.println("This is a dog!");
        return new Dog();
    }
}

参数列表

Parameter List

子类方法的方法名和参数列表必须与父类方法的方法名和参数列表相同。

异常处理

Exceptions

子类方法不能比父类方法抛出更多的异常,可以不抛出异常或者抛出更少的异常。

继承

Inheritance

无法重写无法继承的方法,如父类中访问权限为private的方法。

final 标识

final Keyword

无法重写方法声明为final方法。final 方法可以被继承, 但是不能被重写。

静态方法

static method

无法重写静态方法。不能用子类的非静态方法覆写父类的静态方法,否则编译会报错。

tip提示

《JAVA 编程思想》中多次的提到:方法是静态的、他的行为就不具有多态性。静态方法是与类、而非单个对象相关联的。

方法重载

Overloading

重载是指在同一个类中定义多个方法,它们具有相同的名称但是参数列表不同。 重载的方法必须具有不同的参数列表,可以有不同的返回类型。

三同

Three Same

  • 方法名称相同:要重载的方法名称必须相同。
  • 方法修饰符可以不同:方法的访问修饰符可以相同或不同,但修饰符本身并不作为重载的条件。
  • 返回类型可以不同:重载的方法可以有不同的返回类型,但是不能通过返回类型来区分重载的方法。

三不同

Three Different

  • 参数个数不同:重载的方法可以有不同数量的参数。
  • 参数类型不同:重载的方法可以有不同的参数类型。
  • 参数顺序不同:重载的方法可以有不同的参数顺序(即使参数的数量和类型相同,只要顺序不同,也可以重载)。

隐藏

Hide

隐藏是指子类定义了一个与父类静态方法签名完全相同的静态方法,被称为隐藏。隐藏的方法必须与父类的方法具有相同的名称、参数列表和返回类型。隐藏的方法不能比父类的方法具有更严格的访问权限。

子类隐藏父类的静态方法、变量或内部类,父类和子类各自独立地保留自己的实现。方法调用基于引用类型,而不是实例类型(静态绑定)。 不能用子类的静态方法隐藏父类中的非静态方法,否则编译会报错。

里氏替换原则

Liskov Substitution Principle

里氏替换原则(Liskov Substitution Principle, LSP)是面向对象编程中的五大基本原则之一。 它由 Barbara Liskov 在 1987 年提出,其基本定义是:

如果对每一个类型为 S 的对象 o1,都有类型为 T 的对象 o2, 使得在所有的程序 P 中,o1 替换为 o2 后,程序 P 的行为没有发生变化,那么类型 S 是类型 T 的子类型。 换而言之,在程序中用基类对象的地方都可以使用其子类对象,且程序行为不变。

What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

含义

Meaning

  • 子类必须完全实现父类的方法:子类对父类的方法不能有任何的改动。
  • 子类可以有自己的特性:子类可以增加自己独有的方法,但这些方法不应该影响到父类的方法行为。
  • 子类可以覆盖父类的方法:在保证子类能够替代父类且程序行为不变的前提下,子类可以覆盖父类的方法。

总结

Summary

  • 划清类和对象的界限,它们的作用域是不相同的。
  • 多态是指,针对引用类型的方法调用,其取决于其对象类型的方法。

参考

Reference

Initial Type and Package Type
Git Cheat Sheet