面向对象三大特性:封装、继承、多态。

一、java 多态

生活中,不同人物角色看待同一个对象的视角不同,关注点也不相同。

java设计模式处理多对多关系_System


java中的多态

概念:父类引用指向子类对象,从而产生多种形态。

java设计模式处理多对多关系_java_02


多态是一个实际上是一个小转大的过程。在java中小转大是欢迎的,例如double类型可以接收int型

Dog是继承于Animal,逻辑上狗是属于动物类,所以Dog可以转成Animal

在一个新接触的东西中,在对象里能调用的,我们一般只需要弄懂它对构造方法、属性和方法、继承的影响就行了

(可能开始时候不理解多态的用意,实际上在后续学习中会经常遇到,就会有不同的理解了)

public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
    }  
}

class Animal{}

class Dog extends Animal{}
1.1多态的构造方法

如果是多态,实例化出来的构造方法是先怎样运行的呢?

public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
    }
}

class Animal{
    public Animal(){
        System.out.println("我是动物构造方法");
    }
}

class Dog extends Animal{
    public Dog(){
        System.out.println("我是狗狗的构造方法");
    }
}
运行结果:
我是动物构造方法
我是狗狗的构造方法

可以看到,他是先调用父类的构造方法,再调用子类的构造方法,子类父类的关系没有任何改变

1.2多态的方法与属性

那么接下来添加方法和属性
在这里,我会一只用Animal和Dog例子来说,我们可以在着多态中,将狗对象,当成动物来看待

方法
public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
    }
}

class Animal{
    public void eat(){
        System.out.println("动物要吃");
    }
}

class Dog extends Animal{
    @Override    //重写动物eat方法
    public void eat() {
        System.out.println("狗狗要吃");
    }
}
结果:
狗狗要吃

这个也正常,属于正常的继承关系。

那么如果Dog类对象里有Animal没有的方法呢?

public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.run();     //报错

    }
}

class Animal{
    public void eat(){
        System.out.println("动物要吃");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗狗要吃");
    }
    
    public void run(){
        System.out.println("狗狗要跑");
    }
}
结果:
报错:Cannot resolve method 'run()' 
找不到run方法

在多态里,我们只能调用父类有的方法,而不能调用子类独有的方法。

属性

属性是否也像上面的例子一样,只能调用父类有的属性,不能调用子类独有有的属性呢?

public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
        //调用属性
        System.out.println(animal.breed);
        System.out.println(animal.age);

    }
}

class Animal{
    public String breed = "动物";
    public int age = 18;
}

class Dog extends Animal{
    public String breed = "狗";
    public int age = 8;
}
结果:
动物
18

Dog:震惊!我调用属性的结果,既然是用Animal(父类)的!!

多态里,我用的方法是自己的,用的属性是父类的(这原因是Java编译的静态动态问题,只知道结果就好了)

那么我们方法中调用的值是父类的还是子类的?

public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.method();
    }
}

class Animal{
    public String breed = "动物";
    public int age = 18;

    public void method(){
        System.out.println("我是" + breed + ",今年:"+age + "岁");
    }
}

class Dog extends Animal{
    public String breed = "狗";
    public int age = 8;

    @Override
    public void method() {
        System.out.println("我是" + breed + ",今年:"+age+"岁");
    }
}
结果:
我是狗,今年:8岁

可以看到在方法里调用属性是自己的属性,不是父类的属性。

Dog: 还好我自己方法里调用的属性是自己的,不然我两也太乱了。

Animal:但是如果你不重写我的method方法,直接调用,是调用我的属性值的

Dog:这不是正常的继承关系是这样的吗?我继承了你,但我没有重写方法,所以调用的是你的方法啊… …

Animal:正常个屁,无论是否多态实例化的, 你懒得写,调用的方法甚至里的属性都是用我的

Dog:大家都用你不好吗,谁叫你是老大

在不重写的前提下,我们对比一下正常的实例化和多态的实例化

public class Demo01 {
    public static void main(String[] args) {
        //多态的
        Animal animal = new Dog();
        animal.method();
        //正常实例化的
        Dog dog = new Dog();
        dog.method();
    }
}

class Animal{
    public String breed = "动物";
    public int age = 18;

    public void method(){
        System.out.println("我是" + breed + ",今年:"+age);
    }
}

class Dog extends Animal{
    public String breed = "狗";
    public int age = 8;
}
结果:
我是动物,今年:18
我是动物,今年:18

可以看到,多态实例化的和普通实例化的结果一样

子类独有的属性多态中可以用吗?

public class Demo01 {
    public static void main(String[] args) {
        //多态的
        Animal animal = new Dog();
        System.out.println(animal.hobby);   //报错
    }
}

class Animal{
    public String breed = "动物";
    public int age = 18;
    
}

class Dog extends Animal{
    public String breed = "狗";
    public int age = 8;
    public String hobby = "eat";      //多个这个属性
}
结果:
报错,Cannot resolve symbol 'hobby'
找不到hobby属性

和方法一样,多态只能调用的是父类有的属性,自己独有的不能调用

Animal:你想模仿我,就要按着我的模板来,我有什么你就有什么,但你有独有的就不能用,像什么hobby = “eat”,我可不像你一样就知道吃。

Dog:别说了…

Animal:在多态里,你不能用自己的属性和方法来,这是你品种的特征和行为,不是我的,也别和我扯上

二 、装箱、拆箱

装箱就是小转大,拆箱就是大转小(强转)

  • 向上转型,子类转成父类 由小转成大
    Animal animal = new Dog();
  • 向下转型,父类转成子类 由大转成小
    Animal animal = new Dog();
    Dog dog = (Dog)animal;------------强行转换
三、instanceof关键字

向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性。

语法:父类引用 instanceof 类型 //返回boolean类型结果

java设计模式处理多对多关系_父类_03


多态的典型例子

public class Demo01 {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        animalEat(dog);
        animalEat(cat);
    }

    public static void animalEat(Animal animal){
        if(animal instanceof Cat){
            ((Cat) animal).catEat();   //--------------->强转
        }else if(animal instanceof Dog){
            ((Dog) animal).dogEat();   //--------------->强转
        }
    }
}

class Animal{
}

class Cat extends Animal{
    public void catEat(){
        System.out.println("猫吃吃");
    }
}

class Dog extends Animal{
    public void dogEat(){
        System.out.println("狗吃吃");
    }
}
结果:
狗吃吃
猫吃吃

在这里,我们有时候需要把一个类作为参数,如果没有多态,我们就需要创建两个 animalEat()方法,如果我需要更多的类呢,那不是需要创建更多的对应方法?

所以多态可以说是极大便利了我们的代码,是java类里面比较抽象的知识点之一,先知道怎么用,调用的结果是什么就好了。