Polymorphism
Polymorphism:多态。多态是继抽象、继承之后java的第三种基本特征。它从另一角度将接口和实现分离开来,多态不但能改善代码的组织结构和可读性,还有
利于程序的可扩展性。我们知道继承允许将对象视为它本身的类型或其基类类型来处理;这种能力是很给力的,因为它允许将多种类型(从同一基类导出的)视为
同一类型来处理,而同一份代码也可以毫无差别地运行在这些不同类型之上了。多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要他们是从同一
基类导出来的。这种区别是根据方法行为的不同而表示出来的,虽然这些方法都可以通过同一个基类来调用。java中的所有方法都是通过动态绑定来实现多态的,
所以我们可以编写只与基类打交道的代码,并且这些代码对所有的导出类都可以正确执行。所谓动态绑定,就是在编译时,通过基类引用无法知道具体调用哪个方法,
那么在运行时通过根据对象的类型判断去具体绑定调用的方法;java中除了静态和final方法外,其他所有方法都是动态绑定。
1.静态方法是与类,而并非与单个的对象相关联,所以静态的方法不具备多态性。
2.upcasting:向上转型。我们知道对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用;而声名一个基类引用并指向子类对象的操作就是向上转型。
向上转型是安全的,因为基类不会具有大于导出类的接口。但是向上转型会丢失信息,所以我们希望通过向下转型来获取丢失的信息,java中所以转型都会得到类型检查
所以即使是一次简单的加括号形式的类型转换,在进入运行时仍然会对其进行检查,以确保它确实是我们希望的那种类型,如果不是则会抛出ClassCastException。
3.构造器。在导出类的构造体中,如果没有明确指定调用的父类的某个构造器,则会调用父类的默认构造器,如果父类没有默认构造器,则编译器会报错。
构造器的执行过程:首先按照继承层次关系,同一类按照声名顺序调用静态成员变量的初始化或静态代码块;然后按照继承层次关系先调用成员变量的初始化或代码块
(同一类按照声名顺序)其次调用构造器,知道最底层的类。Sandwich.java。
在构造器内部,尽量避免调用可能被子类覆盖的方法,因为根据构造器的执行顺序,父类的构造器在调用被子类覆盖的方法时,子类的该方法所操纵的成员可能还未被
初始化。PolyConstructors.java.
4.Overriding:
--试图用子类的静态方法覆盖父类中同样标识的实例方法是不合法的,编译器将会报错;
--试图用子类的实例方法覆盖父类中同样标识的静态方法是不合法的,编译器会报错;
--试图用子类的实例方法覆盖父类中同样标识的final方法是不合法的(final修饰的方法不能被覆盖),编译器会报错;
——如果子类存在与父类中同样标识的静态方法,子类的静态方法将会被隐藏(即:静态方法不能被覆盖,但此时编译器不会报错),此时,子类的静态方法只能
通过类名调用。StaticPolymorphism.java
——试图覆盖父类的私有实例方法是不能起作用的,即子类中的与父类私有的相同标识的实例方法只能算子类特有的方法(在实际编程中,为了避免混淆,应该避免
在子类中创建与父类私有的实例方法同名的方法)。
——声明为父类的引用如果指向子类对象,则该引用不能调用子类特有的成员和方法;同时,如果父类的非私有方法被子类覆盖,则声明为父类的引用如果指向子类对
象实际会调用子类的方法。PrivateOverride.java
——子类的实例方法覆盖父类相同标识的实例方法时,子类的该方法的返回值可以为父类被覆盖的方法返回值的子类,此为兼容模式的返回值。CovariantReturn.java
——如果父类的方法1里调用了方法2,但子类覆盖了方法2,那么子类对象在调用方法1时,方法1实际调用的是子类的方法2.
总结:在面向对象的程序设计中,我们持有从基类继承而来的相同接口,以及使用该接口的不同形式:不同版本的动态绑定方法。为了在自己的程序中有效的运用多态乃至
面向对象的技术,必须扩展自己的编程视野,使其不仅包括个别类的成员和消息,而且还包括类与类之间的共同特性以及他们之间的关系。