java面向对象(下)-- 多态
多态概述
在设计一个方法时,通常希望该方法具备一定的通用性。例如要实现一个动物叫的方法,由于每种动物的叫声是不同的,因此可以在方法中接收一个动物类型的参数,当传入猫类对象时就发出猫类的叫声,传入犬类对象时就发出犬类的叫声。在同一个方法中,这种由于参数类型不同而导致执行结果各异的现象就是多态。
在java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的允许结果。
方法的重载和方法的重写都是java多态性的不同表现,二者一个是编译时的多态,一个是运行时的多态,当然二者的区别并不局限如此,这里就不一一赘述。
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
以下是一个多态实例的演示,详细说明请看注释:
1 //定义了接口Animal 2 interface Animal { 3 //定义抽象方法 4 void shout(); 5 } 6 //定义了Cat类并实现了Animal接口 7 class Cat implements Animal{ 8 //实现shou()方法 9 public void shout() { 10 System.out.println("喵喵喵....."); 11 } 12 } 13 //定义了Dog类并实现了Animal接口 14 class Dog implements Animal{ 15 //实现shout()方法 16 public void shout() { 17 System.out.println("汪汪汪....."); 18 } 19 } 20 //定义测试类 21 class Example { 22 //定义静态的animalShout()方法,接收一个Animal类型的参数 23 public static void animalShout(Animal an){ 24 an.shout(); 25 } 26 public static void main(String[] args) { 27 Animal an1 = new Cat(); //创建Cat对象,使用Animal类型的变量an1来引用 28 Animal an2 = new Dog(); //创建Dog对象,使用Animal类型的变量an2来引用 29 animalShout(an1); //调用animalShout()方法,将an1作为参数插入 30 animalShout(an2); //调用animalShout()方法,将an2作为参数插入 31 } 32 }
运行结果:
多态不仅解决了方法同名的问题,而且还使程序变得更加灵活,从而有效地提高程序的可扩展性和可维护性。
多态的优点
-
1. 消除类型之间的耦合关系
-
2. 可替换性
-
3. 可扩充性
-
4. 接口性
-
5. 灵活性
-
6. 简化性
对象的类型转换
在多态的学习中,涉及到将子类对象当做父类类型使用的情况,例如上面的:
将子类对象当做父类使用时不需要任何显示地声明,但此时不能通过父类变量去调用子类中的某些方法。
1 //定义了接口Animal 2 interface Animal { 3 //定义抽象方法 4 void shout(); 5 } 6 //定义了Cat类并实现了Animal接口 7 class Cat implements Animal{ 8 //实现shout()方法 9 public void shout() { 10 System.out.println("喵喵喵....."); 11 } 12 //定义sleep()方法 13 void sleep(){ 14 System.out.println("猫在睡觉...."); 15 } 16 } 17 18 //定义测试类 19 class Example { 20 //定义静态的animalShout()方法,接收一个Animal类型的参数 21 public static void animalShout(Animal animal){ 22 animal.shout();//调用传入参数animal的shout()方法 23 animal.sleep();//调用传入参数animal的sleep()方法 24 25 } 26 public static void main(String[] args) { 27 Cat cat = new Cat(); //创建Cat类的实例化对象 28 animalShout(cat);//调用animalShout()方法,将cat作为参数传入 29 30 } 31 }
运行结果:
在main方法中,调用animalShout()方法时传入了参数Cat类型的对象,而方法的参数类型为Animal类型,这便将Cat对象当做父类Animal类型使用,当编译器编译时,发现Animal类中没有定义sleep()方法,从而出现错误,提示找不到sleep()方法。
解决方法:通过强制类型转换将Animal类型的变量强转为Cat类型
运行结果:
将传入的对象有Animal类型转换为Cat类型后,程序可以成功调用shout()方法和sleep()方法。
需要注意的是,在进行类型转换时也可能出现错误,例如在animalShout()方法时传入一个Dog类型的对象,这时进行强制类型转换就会出现错误。
1 //定义了接口Animal 2 interface Animal { 3 //定义抽象方法 4 void shout(); 5 } 6 //定义了Cat类并实现了Animal接口 7 class Cat implements Animal{ 8 //实现shout()方法 9 public void shout() { 10 System.out.println("喵喵喵....."); 11 } 12 //定义sleep()方法 13 void sleep(){ 14 System.out.println("猫在睡觉...."); 15 } 16 } 17 //定义了Dog类并实现了Animal接口 18 class Dog implements Animal{ 19 //实现shou()方法 20 public void shout() { 21 System.out.println("汪汪汪....."); 22 } 23 } 24 //定义测试类 25 class Example { 26 //定义静态的animalShout()方法,接收一个Animal类型的参数 27 public static void animalShout(Animal animal){ 28 Cat cat =(Cat) animal;//将animal类型强转为Cat类型 29 cat.shout();//调用cat的shout()方法 30 cat.sleep();//调用cat的sleep()方法 31 32 } 33 public static void main(String[] args) { 34 Dog dog = new Dog(); //创建Dog类的实例化对象 35 animalShout(dog);//调用animalShout()方法,将cat作为参数传入 36 37 } 38 }
运行结果:
在调用animalShout()方法时,传入一个Dog对象,在强制类型转换时,Animal类型的变量无法强转为Cat类型。
针对这种情况,java提供了一个关键字instanceof,它可以判断一个对象是否为某个类(或接口)的实例或者子类实例,语法格式如下:
对象(或者对象引用变量) instanceof 类(或接口)
接下来对animalShout()方法进行修改
运行结果:
使用instanceof关键字判断animalShout()方法中传入的对象是否为Cat类型,如果是Cat类型就进行强制类型转换,否则就会打印“this animal is not a cat”。
ps:个人学习笔记!!!