种类
- 方法的多态(同一个方法名,不同输出内容),如方法重载,方法覆盖,这些是用来解决不同对象有同一抽象内涵的成员方法
- 对象的多态
- 向上转型
- 向下转型
向上转型
- 解决的问题:具有同一抽象内涵的多个函数方法的唯一不同是形参列表的对象类型不同(这些对象都有一个相同父类),这会导致代码冗余。将多个方法改为将父类类型对象作为形参的一个方法。当调用该方法时,传入子类对象就行,而且传入不同子类对象会输出符合该子类的内容,这个是符合java的传参机制和赋值机制的,编译和运行都不会报错。
- 本质:父类(可以不是直接父类)的引用/变量名可以指向子类的对象
- 语法:
Animal animal = new Cat(); //编译不会报错,运行不会报错
- 细节:
- Animal是animal的编译类型,Cat是运行类型。
- 在编译上,animal是Animal类型,只能调用Animal类的成员。这是因为java开发平台在检查代码编译是否有误时,只知道animal是编译类型Animal。
- 运行时,animal使用的是运行类型Cat,调用的成员从Animal类变为Cat类的成员,需要注意的是Cat的成员也包括父类Animal类的成员。这是因为animal这个引用所指的具体对象是属于Cat类。如果animal调用的成员,Cat类也有,则要分两种情况,第一种情况:调用的是成员变量。那么运行时实际调用的是编译类型的成员变量。 第二种情况:调用的是成员方法,则运行时实际调用的是运行类型的成员方法。
- 代码(为第一种情况的代码和运行情况)
package com.nyj.polymorphism;
public class PolymorphismExercise {
public static void main(String[] args) {
Animal animal = new Cat();
Person person = new Person();
person.feed(animal);
animal = new Dog();
person.feed(animal);
// Dog dog = (Dog) animal; // 向下多态,dog在编译时可以调用子类Dog类的成员变量和方法
// dog.variety = "中华田园犬";
}
}
class Person {
public void feed(Animal animal) {
System.out.println("给" + animal.name + "喂食");
}
public void play(Animal animal) {
}
}
class Animal {
public String name = "动物";
// public Animal(String name) {
// this.name = name;
// }
}
class Dog extends Animal {
public String name = "旺财";
public String variety;
// public Dog(String name) {
// super(name);
// }
}
class Cat extends Animal {
public String name = "吾皇";
// public Cat(String name) {
// super(name);
// }
}
代码运行结果
向下转型
- 解决的问题:使得在编译阶段animal使得调用子类成员。
- 语法:
Animal animal = new Cat(); Cat cat = (Cat)animal;
- 细节
- 只能对编译类型进行强制转换
- 对象的编译类型强制转换后的目标类型必须和对象的运行类型一致
- 代码
Animal animal = new Dog("小狗");
person.feed(animal);
Dog dog = (Dog) animal;
dog.variety = "中华田园犬"; // variety是Dog类的独有属性,dog可以直接调用variety,说明编译上成功
Cat cat = (Cat) animal; // 可以通过编译,但是会报运行错误