多态(polymorphism)
多态
多态:不同的对象调用同一个方法可能会产生不同的行为
eg.
package com.chenxingen; class Pet{ String name;//宠物名 public Pet() { } public Pet(String name) { this.name = name; } public void eat(){ System.out.println("吃东西..."); } } class Cat extends Pet{//猫类 public void eat(){ System.out.println("猫吃鱼..."); } } class Horse extends Pet{//马类 public void eat(){ System.out.println("马吃草..."); } } public class Work241 { //多态 //使用父类作为方法形参 public static void petEat(Pet pet){ pet.eat(); } public static void main(String[] args) { //子类到父类的自动转型 Pet cat=new Cat(); Horse horse=new Horse(); petEat(cat); petEat(horse); } }
注意:多态指的是方法,属性没有多态这个概念
多态存在的必要条件:、
1.继承
首先我们要知道多态的概念,是同一个方法,不同的对象调用会有不同的行为,也就是说不同的对象都必须要有这个同一的方法,显然,如果我们每个都自己定义一个名字相同的方法,是能够做到的,但显然不符合代码的复用性,而多态的存在就是提高代码的复用性,所以我们需要继承,只需要父类中有这个方法,其所有的子类都会有,所以多态存在的第一步必须要继承!
2.方法重写
我们已经实现里多态的第一步,继承!我们知道,我们继承下来的方法都是父类中的,父类写好的方法是不变的,这个时候我们的子类如果不进行重写该方法,那么尽管是不同的对象,当执行该方法的时候,其产生的行为还是一模一样,所以我们必须在子类继承有该方法的父类后,还要对该方法进行重写
3.父类引用指向子类
这个地方需要我们重点理解!!!(下面我们从便于理解的角度来阐述这一点)
如上示例代码中:
public class Work241 { //多态 //使用父类作为方法形参 public static void petEat(Pet pet){ pet.eat(); } public static void main(String[] args) { //子类到父类的自动转型 Pet cat=new Cat(); Horse horse=new Horse(); petEat(cat); petEat(horse); } }
我们知道Pet是父类,cat、horse是子类;
Pet cat=new Cat(); √
这行代码的意思就是:创建一个猫对象,用一个宠物类型的变量类接收,从逻辑上,可以接受!
也就是说:猫是宠物
Cat cat=new Pet(); ×
这行代码的意思就是:创建一个宠物对象,用一个猫类型的变量类接收,从逻辑上,可以接受,但是有歧义,因为宠物不一定就是猫!
而机器语言与自然语言不同,java又是一门严谨的语言,所以这种写法错误!
public static void petEat(Pet pet){
pet.eat();
}
petEat(cat);
这个理解起来应该没有问题,因为本身也是一个Pet类型的变量接受!
Horse horse=new Horse();
petEat(horse);
这个理解起来可能会有些一些问题,因为我们是用Horse变量类型来接受的,而方法中的形参是Pet类型的,两者不一样,但是还是那句话,我们把马当做宠物是完全没有问题的,所以可以这样使用,这种就叫自动类型转换,这也叫做父类引用指向子类对象
Cat cat=new Pet();
cat父类引用,new Pet()子类对象
上述就叫多态,可以看出,这样我们能够大大的提高代码的复用性,如何看出,可以比较
public static void petEat(Pet pet){ pet.eat(); } 等于 public static void petEat(Cat cat){ cat.eat(); } public static void petEat(Horse horse){ horse.eat(); } public static void petEat(... ...){ ....eat(); }
如果不适用多态,随着宠物类型的增多,我们的方法会逐渐增加,代码趋于繁琐…
补充:多态中常犯错误!!!
eg;(编译问题)
seeDoor方法是子类Dog特有的方法,不是重写的方法
此时,我们可以看到,编译报错了!
这是因为在编译的时候,是检查语法错误,而此时new Dog()是用一个动物变量来接受,这并没有错误,但是,在执行dog.seeDoor()时,报错了,因为dog是一个Animal变量,编译器需要去Animal类中查看是否存在一个叫seeDoor的方法,我们知道seeDoor方法是Dog类特有的,在Animal中没有,所以编译器报错了!
那如何处理这种情况呢?
使用强转即可!
eg;(运行问题)
我们创建里一个Dog对象,用Animal类型接收,然后将其强转为Dog类型,强转为Cat类型,都没有错误
因为动物可以是猫,也可以是狗,就像猜盲盒一样,我们知道这个盒子里要么是猫要么是狗,只有打开后,观察其特征,我们才知道其具体是啥,但是我们现在没有具体看到,只知道要么是猫,要么是狗,我们这样去说并没有错,也就是编译检查为什么通过的原因!
问题来了,报错了,运行报错了,盒子打开了,我们知道有人猜错了,有人猜对了,那么我们现在再把盒子关闭,人们都知道里面是狗了!
为里防止这种情况,我们需要借助工具
Pet pet=new Cat(); System.out.println(pet instanceof Pet);//TRUE System.out.println(pet instanceof Cat);//TRUE System.out.println(pet instanceof Horse);//FALSE
Instanceof是二元运算符,左边是对象,右边是类:当对象是右边类或者子类所创建对象时,返回true