多态

44 阅读3分钟

多态:统一方法的调用,由于对象不同可能会有不同的行为。

现实生活中,同一个方法,具体实现会完全不同。比如:同样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。

多态的要点

  1. 多态是方法的多态,不是属性的多态(多态与属性无关)
  2. 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类的对象
  3. 父类引用指向子类的对象后,用该父类引用调用子类重写的方法,此时多态就出现了
package testduotai;

public class Animal {
    public void shout() {
        System.out.println("叫了一声");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}

多态的使用示例

package testduotai;

public class TestPolym {
    public static void main(String[] args) {
        animalCry(new Dog()); // 子类对象
        animalCry(new Cat()); // 子类对象
    }

    static void animalCry(Animal a) { // 父类引用指向子类对象
        a.shout();  // 父类应用子类重写的方法,出现多态
    }
}

image.png

  1. 如果不适用多态就得这样写:需要写很多重载方法,非常麻烦
package testduotai;

public class TestPolym {
    public static void main(String[] args) {
        animalCry(new Dog());
        animalCry(new Cat());
    }

    static void animalCry(Dog d) {
        d.shout();
    }

    static void animalCry(Cat c) {
        c.shout();
    }
}

总结:由此我们看出了多态主要是为了提高代码的可拓展性。但是多态也有弊端,就是无法调用子类特有的功能,例如上述Dog的seedoor方法,那如果我们想用子类的特有方法呢??该如何处理

例如:

package testduotai;

public class TestPolym {
    public static void main(String[] args) {
        Animal d = new Dog(); // 向上自动转型
        animalCry(d);
        Animal c = new Cat(); // 向上自动转型
        animalCry(c);

        // 如果想调用Dog 的seedoor 方法,以下写法编译不通过
        d.seedoor(); // 无法解析seedoor,编译不通过,因为d属于编译类型,Dog对象才是运行时类型;
    }

    static void animalCry(Animal a) {
        a.shout();
    }
}

对象的转型

  1. 父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换;
  2. 向上转型后的父类引用变量,只能调用它编译类型的方法,无法调用它运行时类型的方法,例如:
public class TestPolym {
    public static void main(String[] args) {
        Animal d = new Dog(); // 向上自动转型的父类引用变量
        d.shout();  // 可以访问 编译类型的方法shout()
        d.seedoor(); // 报错,无法访问 运行时的方法seedoor()
    }

    static void animalCry(Animal a) {
        a.shout();
    }
}

所以想要方法d的seedoor(),需要对父类引用变量d进行类型的强制转换,我们称为向下转型

package testduotai;

public class TestPolym {
    public static void main(String[] args) {
        Animal d = new Dog(); // 向上自动转型
        Dog d1 = (Dog)d; // 向下转型
        d1.seedoor();
    }

    static void animalCry(Animal a) {
        a.shout();
    }
}

image.png

注意:在向下转型过程中,必须将引用变量转换为真实的子类类型(运行时类型),否则会出现类型转换异常,如图:

image.png

为了避免出现这种异常,我们可以使用instanceof运算符进行判断。

image.png