多态:面向对象三大特征之一
面向对象三大特征:封装、继承、多态
封装:面向对象三大特征之一 - 鹿先森JIAN - 博客园 (cnblogs.com)
继承:面向对象三大特性之一 - 鹿先森JIAN - 博客园 (cnblogs.com)
多态概述:
多态(Polymorphism)的前提是封装形成独立体,独立体之间存在继承关系,从而产生多态机制。
多态就是“同一个行为”发生在 “不同的对象上” 会产生不同的效果。
在 java 中允许这样的两种语法出现:
向上转型(Upcasting),是指子类型转换为父类型,又被称为自动类型转换
向下转型(Downcasting),是指父类型转换为子类型,又被称为强制类型转换。
多态的语法:
达到多态三个必要条件:1.继承 2.方法重写 3.向上转型(自动类型转换)
特点:多态形式,只能调用重写的方法,执行的是子类的方法;不能调用子类独有的方法!
public class Animal { public void eat(){ System.out.println("Animal.eat..."); } } //---------------------- public class Cat extends Animal{ @Override public void eat() { System.out.println("Cat.eat..."); } void catchMouse(){ System.out.println("猫抓老鼠。。。"); } } //------------------------ public class Dog extends Animal { @Override public void eat() { System.out.println("Dog.eat..."); } void lookDoor(){ System.out.println("狗看门。。。"); } } //------------------------- public class Test { public static void main(String[] args) {
Animal a1 = new Cat(); Animal a2 = new Dog(); //向上转型(自动) a1.eat();
a2.eat(); } }
执行结果:
Cat.eat...
Dog.eat...
我们现在让多态创建出来的猫对象,去抓老鼠
编译报错,因为 catchMouse()方法属于子类Cat 中独有的行为,如果想要调用抓老鼠的方法,我们可以将对象向下转型为猫对象
既然这样,能将 Cat类转为 Dog类,然后调用Dog类特有的lookDoor()方法吗?
运行报错:ClassCastException,翻译为类型转换异常
因为 a1引用指向的对象是一只 Cat,然后我们要将一只Cat强制转换成一只 Dog,这显然是不合理的,因为 Cat和 Dog之间是没有继承关系的。为了避免这种异常的发生,建议在进行向下转型之前进行运行期类型判断,这就需要我们学习一个运算符了,它就是 instanceof 关键字
下面代码中:a1 instanceof Dog,翻译为:a1引用的对象,是不是 Dog类型?True 或 False
执行结果:类型不匹配
------------------------------------------------------------------------------------
package test; //饲养员类 public class AnimalKeeper { private String name; //提供getter和setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } //无参构造 public AnimalKeeper() {} 有参构造 public AnimalKeeper(String name) { this.name = name; } // public void feed(Cat cat){ // System.out.println(name+"喂猫"); // } // public void feed(Dog dog){ // System.out.println(name+"喂狗"); // } public void feed(Animal animal){ //类作为参数类型 System.out.println(this.name+"在喂动物"); animal.eat(); } } //--------------------------- package test; public class Test { public static void main(String[] args) { Cat c1 = new Cat(); Dog d1 = new Dog(); AnimalKeeper a1 = new AnimalKeeper("小明"); a1.feed(c1);
a1.feed(d1); } }
执行结果:
小明在喂动物
Cat.eat...
Dog.eat...
在以上程序中,AnimalKeeper 类中的方法feed(Animal animal) 的参数类型定义为更加抽象的Animal 类型,而不是feed(Dog dog) 或 feed(Cat cat),显然AnimalKeeper 类和具体的Dog、Cat 类解耦合了,依赖性弱了,这就是我们通常所说的面向抽象编程,尽量不要面向具体编程,面向抽象编程会让你的代码耦合度降低,扩展能力增强。如果想新增一个 Bird类,只需在Test 类里:Bird b =new Bird(); a1.feed(b); 就可以了,多方便,也不用再 AnimalKeeper类写了。