概述
- 一个对象对应多种类型
- 同一个行为具有多个不同表现形式或形态的能力
- 多态在代码中的体现:父类或接口的引用指向其子类对象
利弊
好处:
- 提高代码的可扩展性,方便后期维护 (后期添加的子类对象可使用前期父类或接口定义的方法)
弊端:
- 子类特有的方法无法被父类/接口的引用对象所调用
`PolymorphismDemo.java`
abstract class Animal{
public abstract void eat();
}
class Cat extends Animal{
public void eat(){
System.out.println("cat eat");
}
public void catchMouse(){
System.out.println("cat catch mouse");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("dog eat");
}
public void protectHome(){
System.out.println("dog protect home");
}
}
class PolymorphismDemo{
public static void main(String[] args){
Cat c = new Cat();
Dog d = new Dog();
// c.eat();
// d.eat();
// 提高代码复用性——method()
method(c);
method(d);
}
/*
public static void method(Cat c){
c.eat();
c.catchMouse();
}
public static void method(Dog d){
d.eat();
}
// 为子类的引用,后期出现新的子类对象则需要添加对应的新的方法
*/
// 父类的引用,则后期新的对象只要属于其子类皆可使用之前的方法
public static void method(Animal a){
a.eat();
// a.catchMouse(); ————>wrong (子类特有方法)
}
}
前提:
- 对象与类型要有关系———继承、实现
- 要有覆写(重写) –
Override
向上、向下转型
缘由
- 向上转型:提高程序扩展性,限制对特有功能的访问
- 向下转型:为了使用子类中的特有方法
- 仅是对同一子类对象的类型转换
// 续 PolymorphismDemo.java
// 1.向上转型
Animal a = new Cat();
//类似自动类型提升
a.eat(); // 但无法访问特有功能
// 2.向下转型
Cat c = (Cat)a;
c.eat();
c.catMouse(); // 为了使用子类的特有功能
// 注意:
// 对于转型,只涉及同一子类对象类型的转换
Animal a1 = new Dog();
Cat c1 = (Cat)a1; //————wrong
//ClassCastException 类型转换错误
转型后,父类子类、静态非静态方法/属性 调用问题
- 父类Animal
public class Animal {
public String name = "父类Animal共同非静态属性:name";
public static String staticName = "父类Animal静态属性:staticName";
public void eat() {
System.out.println("父类Animal共同非静态方法:eat()");
}
public static void staticEat() {
System.out.println("父类Animal共同静态方法:staticEat()");
}
}
- 子类Pig
public class Pig extends Animal {
public String name = "子类Pig共同非静态属性:name";
public static String staticName = "子类Pig共同静态属性:staticName";
public String str = "子类Pig独有非静态属性:str";
public void eat() {
System.out.println("子类Pig共同非静态方法:eat()");
}
public static void staticEat() {
System.out.println("子类Pig共同静态方法:staticEat()");
}
public void pigEat() {
System.out.println("子类Pig独有非静态方法:eatMethod()");
}
public static void main(String[] args) {
// 1. 向上转型
Animal animal = new Pig();
animal.eat(); // 子类Pig共同非静态方法:eat()
animal.staticEat(); // 父类Animal共同静态方法:staticEat()
//animal.pigEat(); // 编译出错,The method eatMethod() is undefined for the type Animal -- 父类无法使用子类独有方法
System.out.println(animal.name); // 父类Animal共同非静态属性:name
System.out.println(animal.staticName); // 父类Animal静态属性:staticName
System.out.println(animal.staticAlone); // 父类Animal独有静态属性:staticAlone
//System.out.println(animal.str); // 编译出错,str cannot be resolved or is not a field -- 父类无法使用子类独有属性
// 2. 向下转型
Pig pig = (Pig) animal;
System.out.println(pig.name); // 子类Pig共同非静态属性:name
System.out.println(pig.staticName); // 子类Pig共同静态属性:staticName
System.out.println(pig.str); // 子类Pig独有非静态属性:str
pig.pigEat(); // 子类Pig独有非静态方法:eatMethod()
pig.staticEat(); // 子类Pig共同静态方法:staticEat()
}
}
-
类 – 编译时确定,实例 – 运行时确定 (后面)
-
向上转型后,引用变量属于父类,静态方法和属性 – 使用父类(父类中一定要存在对应属性或非静态方法,否则编译失败,即使子类存在对应变量),非静态方法 – 如果子类覆写该方法(即子类中存在同名方法),优先使用子类,否则使用父类
-
向下转型后,引用变量属于子类,同时子类继承父类方法(子类会继承父类所有属性和方法(静态和非静态都继承)),所以无论静态非静态,都优先使用子类,子类不存在,再使用父类方法或属性(静态非静态都可)
-
向上转型特点 (编译运行区别) – Java – 属性和静态非静态方法 编译时和运行时的区别
对象类型判断
-
关键字——
instanceof
-
用于判断子类对象的具体类型,只能用于引用数据类型判断
public static void method(Animal a){
a.eat();
if(a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog){
Dog d = (Dog)a;
d.protectHome();
}
// a instanceof Animal==True
}
注意
:
- 如您发现本文档中有错误的地方,
- 或者您发现本文档中引用了他人的资料而未进行说明时,请联系我进行更正。
- 转载或使用本文档时,请作说明。
- 非常感谢
:)