一、多态的概念
通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
二、实现多态的条件
在Java中实现多态,需要满足几个条件:
- 必须是在继承关系上,因为在继承关系上才能发生向上转型。
- 子类和父类必须有同名的方法。(重写/覆盖的方法)
- 通过父类对象的引用,去调用这个重写的方法。
- 完成以上三部分,就会发生动态绑定,而动态绑定是多态的基础。
那什么是向上转型呢?
是:当我们把子类对象给到父类之后,这个过程就是向上转型。
向下转型就是:当我们把父类对象给到子类之后,这个过程就是向下转型。
现在假设有Animal类,Dog类继承于Animal。代码如下:
class Animal{ public String name; int age; public Animal(String name,int age){ this.name=name; this.age=age; } public void eat(){ System.out.println(this.name+"正在吃饭!"); } }
class Dog extends Animal{ public Dog(String name,int age){ super(name, age); } public void bark(){ System.out.println(this.name+"正在汪汪叫!"); } }
现在我们在main方法里面把子类对象给到父类,即把dog类对象让Animal类的对象去引用。
public class Test { public static void main(String[] args) { //Dog dog=new Dog("大黄",5); //Animal animal=dog;和下行代码等价 Animal animal=new Dog("圆圆",19); } }
这样,animal这个引用就指向了dog这个引用所指向的对象,便发生了向上转型。
当然,向上转型也不只是这一种方法。下面来看:
public class Test { public static void func1(Animal animal){ //... } public static void main(String[] args) { Dog dog =new Dog("圆圆",19); func1(dog); } } //相当于还是让父类引用指向了子类引用所指的对象,只不过是通过方法传参实现
public static Animal func2(){ Dog dog=new Dog("圆圆",19); return dog; }//返回值用Animal类来接收
综上所述,常见的可以发生的向上转型的3个时机:
- 直接赋值
- 方法传参传参的时候,进行向上转型
- 返回值向上转型
理解了向上转型之后,我们在Dog类中进行一个小小的修改:
在Dog类里面添加一个eat方法:
class Dog extends Animal{ public Dog(String name,int age){ super(name, age); } public void bark(){ System.out.println(this.name+"正在汪汪叫!"); } @Override public void eat() { System.out.println(this.name+"正在吃狗粮!"); } }
而父类Animal类中也有eat方法,通过下面的对比:
接着,在main方法中,让animal这个对象去调用eat方法。运行结果如下:
public static void main(String[] args) { Animal animal =new Dog("圆圆",19); animal.eat(); }
通过运行结果发现:animal这个父类引用调用了Dog类里面的eat方法,我们一般会认为animal只能调用自己类里面的eat方法,那这是为什么?
原因是:这两个类发生了重写,而在main方法里面,通过父类的引用进行调用这个重写的方法的时候,就会调用子类的eat方法。
我们把这个过程就叫做动态绑定。
- 注意:被重写的方法的访问限定修饰符,在子类中要大于等于父类的。
- 被private修饰的方法是不能被重写的。
- 被static修饰的方法是不能被重写的。
- 被final修饰的方法也是不能被重写的。
那怎么理解动态绑定呢?
动态绑定,就是在程序运行的时候绑定到了子类的重写方法上。
在cmd上运行这段代码:
下面,我们继续在原来的代码基础上,再加一个Cat类,并且把eat重写,同样继承于Animal类:
class Cat extends Animal{ public Cat(String name,int age){ super(name, age); } public void miaomiao(){ System.out.println(this.name+"正在咪咪叫!"); } @Override public void eat() { System.out.println(this.name+"正在吃猫粮!"); } }
在main方法中,加入一个func方法:
public static void func(Animal animal){ animal.eat(); }
站在func这个方法的角度看,当给它传的参数不同的时候,它调用的eat方法所能够表现出来的行为也是不一样的。
public static void main(String[] args) { Dog dog =new Dog("圆圆",19); func(dog); Cat cat=new Cat("猫咪",12); func(cat); }
运行结果如下:
总结:
当父类引用,引用的子类对象不一样的时候,调用这个重写的方法,所表现出来的行为是不一样的!!!我们把这种思想就叫做多态!