多态
理解多态之前,要先明白什么是向上转型和动态绑定。这个向上转型字面上的意思就是子类--->父类。我们在实例化一个鸟类时,可以这样写:
Bird bird = new Bird("jj");
或者:
Bird bird = new Bird("jj");
Animal bird1 = bird;
//两行代码组合起来
Animal animal = new Bird("jj");
此时
animal
是一个父类
(Animal)
的引用
,
指向一个子类
(Bird)
的实例,这种写法就是向上转型。
我们看代码是从后往前看,相当于是把一个鸟类对象赋值给了父类对象,由子类到父类的转变,就是向上转型。
发生向上转型有三种形式,第一种就是上面演示的,直接赋值。还有两种分别是方法传参和方法返回。
public class Test {
public static void main(String[] args) {
Bird bird = new Bird("jj");
feed(bird);
}
public static void feed(Animal animal) {
animal.eat("谷子");
}
}
这是通过方法feed把bird传给animal,所谓方法传参。
public class Test {
public static void main(String[] args) {
Animal animal = findMyAnimal();
}
public static Animal findMyAnimal() {
Bird bird = new Bird("圆圆");
return bird;
}
}
这是通过findMyAnimal方法返回一个bird给animal,所谓方法返回。
下面说动态绑定。
package demo1;
public class Bird extends Animal{
Bird(String name){
super(name);
}
public void eat(){
System.out.println("我调用的是Bird的eat方法!");
System.out.println(name+"正在吃谷子!");
}
}
class Animal{
public String name ;
public int age;
public Animal(String name){
this.name = name;//构造方法
}
public void eat(){
System.out.println("我调用的是Animal的eat方法!");
System.out.println(name+"正在吃饭!");
}
public void run(){
System.out.println(name+"正在跑!");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal("jj");
animal.eat();
Animal animal1 = new Bird("kk");
animal1.eat();
}
}
看以上代码,当父类和子类有同名的方法时,程序会调用哪个eat方法呢?这就要看调用方法的引用到底是指向父类对象还是子类对象。animal是指向父类Animal的引用,所以animal.eat()自然就调用父类Animal自己的eat方法,而animal1是指向子类Bird的引用,所以animal1调用的就是Bird的eat方法。在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引 用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为动态绑定。以上代码的运行将结果如下:
以上代码提到了父类和子类有相同的eat方法,这种子类实现父类的同名方法, 并且参数的类型和个数完全相同,叫做方法的重写。注意,重载和重写是有区别的。重载是有相同的方法名称,但是参数不同,这个不同可以是类型不同(add(int num1) add(double num1)),个数不同(add() add(int num1) add(int num1,int num2)),顺序不同(add(int num1,double num2) add(double num1,int num2)。方法的重载只跟方法名和形参列表有关,与修饰符,返回值类型无关。而重写是发生在父子类继承关系中的,方法名和参数列表必须完全一致,只是具体的实现不同。
理解了向上转型和动态绑定之以及方法的重写后,就可以去讲多态了。
package demo1;
class Animal{
public String name ;
public int age;
public Animal(String name){
this.name = name;//构造方法
}
public void eat(){
System.out.println("我调用的是Animal的eat方法!");
System.out.println(name+"正在吃饭!");
}
}
class Dog extends Animal{
public Dog(String name){
super(name);
}
public void eat(){
System.out.println("我调用的是Dog的eat方法!");
System.out.println(name+"正在吃狗粮!");
}
}
class Cat extends Animal{
public Cat(String name){
super(name);
}
public void eat(){
System.out.println("我调用的是Cat的eat方法!");
System.out.println(name+"正在吃猫粮!");
}
}
class Bird extends Animal{
Bird(String name){
super(name);
}
public void eat(){
System.out.println("我调用的是Bird的eat方法!");
System.out.println(name+"正在吃谷子!");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog("小狗");
Animal animal2 = new Cat("小猫");
Animal animal3 = new Bird("小鸟");
allEat(animal1);
allEat(animal2);
allEat(animal3);
}
public static void allEat(Animal animal){
animal.eat();
}
}
看以上代码,我们只用了一个Animal的引用,却能表现出多种不同的形态(狗就是吃狗粮,猫就是吃猫粮,鸟就是吃谷子),这就是多态。发生多态的前置条件就是要先向上转型,在动态绑定(其中又涉及到了方法的重写),之后在发生多态。
使用多态的好处是什么呢?
封装是让类的调用者不需要知道类的实现细节 . 多态能让类的调用者连这个类的类型是什么都不必知道 , 只需要知道这个对象具有某个方法即可 因此 , 多态可以理解成是封装的更进一步 , 让类调用者对类的使用成本进一步降低。 标签:系列,面向对象编程,void,public,Animal,Bird,eat,name From: https://blog.csdn.net/qq_74482991/article/details/142885959