面向对象程序设计的三大支柱是封装、继承和多态。本篇文章主要讲述多态的相关知识。
一、概述
1.定义
多态意味着父类的变化可以指向子类对象;它是同一行为具有不同表现形式或形态的能力。
ps:一个类实际定义了一种类型。子类定义的类型称为子类型;父类定义的类型称为父类型。
2.要实现多态需要满足一下几个条件:
- 有继承关系
- 有方法重写(抽象方法)
- 有父类引用指向子类对象
3. 多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
4. 多态的弊端
(1)不能使用子类的特有功能
如果想使用,一种方法就是创建子类对象调用方法(可以但是很多时候不合理,而且太占内存),另一种方式把父类的引用强制转换为子类的引用(向下转型)
(2)对象间的转型问题
向上和向下,其实就是父和子的关系,父为上,子为下。
向上转型
Fu f = new Zi();
向下转型
Zi z = (Zi)f; // 要求f必须能够转为Zi
举例说明
class Fu {
public void show() {
System.out.println("show Fu");
}
}
class Zi {
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method Zi");
}
}
class DuoTaiDemo2 {
public static void main(String[] args) {
Fu fu = new Zi();
fu.show();
// fu.method(); 错误,不能使用子类特有功能
// 通过转型可以使用子类特有功能
// 创建子类对象
// 可以但是不推荐
Zi zi = new Zi();
zi.show();
zi.method();
// 要求f必须能够转为Zi
// 推荐()
Zi zi2 = (Zi)fu;
}
}
5.与生活中的实例进行类比
现实中,比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
二、格式
parent p = new Chile();
- 把子的对象赋值给父
- 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
这里先举几个例子帮助大家理解:
例1
public class PolymorphismDemo{
public static void main(String[] args){
displayObject(new CircleFromSimpleGeometricObject(1,"red",false));
displayObject(new RectangleFromSimpleGeometricObject(1,"red",true));
}
public static void displayObject(SimpleGeometricObject object){
System.out.prinyln("Created on"+object.getDateCreaded()+".Color is"+object.getColor());
}
}
运行结果:
Created on Mon Mar 09 19:25:20 EDT 2011.Color is red
Created on Mon Mar 09 19:25:20 EDT 2011.Color is black
方法displayObject 具有GeometricObject类型的参数。可以通过传递任何一个GeometricObject的实例和new CircleFromSimpleGeometricObject(1,"red",false)来调用displayObject 。使用父类对象的地方都可以使用子类对象。这就是通常所说的多态。
例2
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
运行结果:
吃鱼 抓老鼠 吃骨头 看家 吃鱼 抓老鼠
三、多态中成员的访问方法
在学习多态时,有一句广为流传的口诀:编译看左边,运行看右边。但其实它是针对非静态方法说的,而成员变量、静态方法都是只看左边。
下面举一个例子来证明上述结论:
父类
public class Father {
int num = 520;
static void staticMethod() {
System.out.println("父类静态方法");
}
void normalMethod() {
System.out.println("父类普通方法");
}
}
子类
class Son extends Father {
int num = 1314;
static void staticMethod() {
System.out.println("子类静态方法");
}
@Override
void normalMethod() {
System.out.println("子类普通方法");
}
}
测试类
class Test {
public static void main(String[] args) {
Father f = new Son();
// 与父类一致
System.out.println(f.num);
// 与父类一致
f.staticMethod();
// 编译时与父类一致,运行时与子类一致
f.normalMethod();
Son z = new Son();
System.out.println(z.num);
z.staticMethod();
z.normalMethod();
}
}
运行结果
520
父类静态方法
子类普通方法
1314
子类静态方法
子类普通方法
四、多态的实现形式
1.重写
2.接口
- 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
- java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。