Java的多态

Java的多态

文章目录

    • Java的多态
      • 多态的概念
      • 多态实现条件
      • **什么是向上转型呢?**
      • **什么是重写?**
      • **什么是动态绑定?**

多态的概念

​ 通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。 总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。

多态实现条件

java中要实现多态,必须要满足如下几个条件,缺一不可:

  1. 必须在继承体系下,完成向上转型
  2. 子类必须要对父类中方法进行重写
  3. 通过父类的引用调用重写的方法(动态绑定)

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。(动态绑定)

什么是向上转型呢?

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()

向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法。

class Animal {
    String name;
    int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(name + "吃饭");
    }
}
class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }
   public void action(){
       System.out.println(name + "小猫抓老鼠");
   }
}
public class TestAnimal1 {
    public static void main(String[] args) {
        //向上转型 父类引用animal 引用了子类的对象
        Cat cat1 = new Cat("小猫1", 2);
        Animal animal = cat1;
        //简洁写法(推荐)
        Animal animal2 = new Cat("小猫2", 2);
        animal2.eat();
        //不可以调用action方法,因为此时通过父类引用只能调用父类的属性和方法了
        animal2.action();//(报错)
        //解决办法: 再向下转型到具体要调用的子类.
        Cat cat = (Cat) animal2;
        cat.action();
    }
}

什么是重写?

​ 重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, **返回值和形参都不能改变。即外壳不变,核心重写!**重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写满足重写的条件

1.方法名相同

2.方法的参数列表相同(参数个数, 参数类型, 参数顺序)

3.方法的返回值相同.(父类的返回值和子类的返回值是父子类关系也可以.这种情况叫协变类型)

4.static 的方法不能被重写

5.private 修饰的方法不能被重写

6.子类的修饰访问符,需要大于等于父类的访问修饰符

重写和重载的区别

Java的多态_第1张图片

Java的多态_第2张图片

即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

什么是动态绑定?

静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。典型代表方法重写

class Animal {
    String name;
    int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(name + "吃饭");
    }
}
class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(name + "吃鱼~~~");
    }
}
class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(name + "吃骨头~~~");
    }
}
public class TestAnimal {
    // 编译器在编译代码时,并不知道要调用Dog 还是 Cat 中eat的方法
    // 等程序运行起来后,形参a引用的具体对象确定后,才知道调用那个方法
    // 注意:此处的形参类型必须时父类类型才可以
    public static void eat(Animal a) {
        a.eat();
    }
    public static void main(String[] args) {
        Cat cat = new Cat("小猫", 2);
        Dog dog = new Dog("小狗", 1);
        eat(cat);
        eat(dog);
    }
}
运行结果
    小猫吃鱼~~~
	小狗吃骨头~~~

Java的多态_第3张图片

注意: 避免在构造方法中调用重写的方法

class B {
    public B() {
    //避免在构造方法中调用重写的方法,会发生不易察觉的错误
        func();
    }
    public void func() {
        System.out.println("B.func()");
    }
}
class D extends B {
    private int num = 1;
    @Override
    public void func() {
        System.out.println("D.func() " + num);
    }
}
public class Test {
    public static void main(String[] args) {
        D d = new D();
    }
}
//  运行结果:
//  D.func() 0

ntln("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
// 运行结果:
// D.func() 0


原因: 构造 D 对象的同时, 会先调用 B 的构造方法.B 的构造方法中调用了 `func` 方法, 
此时会触发动态绑定, 会调用到 D 中的 `func`方法, 但是此时 D 对象自身还没有构造, 
所以 `num` 处在未初始化的状态, 值为 0.

你可能感兴趣的:(JavaSE,java,开发语言)