zoukankan      html  css  js  c++  java
  • Java基础00-多态19

    1. 多态

    多态

    1.1 多态概述

    代码示例:

    动物类:

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

    猫类:

    多态的前提有继承/实现关系,所以猫类要继承动物类。

    public class Cats extends Animal {
    
    }

    多态的前提要有方法重写,所以要重写父类的eat()方法。

    public class Cats extends Animal {
    
        @Override
        public void eat(){
            System.out.println("猫吃鱼");
        }
    }

    实现类:

    要有父类引用指向子类对象

    public class AnimalDemo {
        public static void main(String[] args) {
            //有父类引用指向子类对象
            Animal a = new Cats();  
        }
    }

    这样就满足了多态的前提,这样的现象就称之为多态。

    1.2 多态中成员和成员变量访问特点

    • 访问成员变量的特点:

        直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
        间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。

    • 访问成员方法的特点:

        看new的是谁,就优先用谁,没有则向上找。

    代码示例:

    动物类:

    public class Animal {
        int age = 40;
        public void eat(){
            System.out.println("动物吃东西");
        }
    }

    猫类:
    继承了动物类,并重写的父类的eat()方法

    public class Cats extends Animal {
    
        public int age = 20;
        public int weight = 10;
        
        @Override
        public void eat(){
            System.out.println("猫吃鱼");
        }
    
        public void playGame(){
            System.out.println("猫捉迷藏");
        }
    }

    测试类:
    a.age调用可以使用,但是a.weight调用不可以使用,
    因为,虽热内存中指向的是子类new Cat(),但是外界看到的是Animal a,通过多态的方式在访问成员变量的时候它的编译要看左边(父类),要看左边(父类)中有没有,有就可以调用,没有就不可以调用。

    接下来运行测试类:
    通过多态的形式,去访问成员变量,其实是访问左边(父类)中的,所以,通过多态的形式,访问成员变量,它的编译看右边,运行也看右边。

    接下来调用成员方法:
    调用a.eat()方法成功,a.playGame()失败,
    可见调用成员方法和变量是一样的,编译也要看左边(父类),右边有可以通过,没有就不可以。

    运行测试类:
    运行的是重写后的方法,由此可见
    通过多态的方式,调用成员变方法看的是右边(子类),运行看右边

    1.3 多态的好处和弊端

    代码示例:

    类目录:

    动物类:

    猫类:

    猫类继承了动物类并重写了它的eat()方法。

    动物操作类:

    它的成员方法的形成类型是Cat。

    测试类:

    运行测试类并调用操作类的方法:

    运行:

    ao.useAnimal©,解析:
    调用ao(操作类)中的useAnimal成员方法,
    useAnimal方法的形参类型是Cat(猫类),
    所以将main方法中的Cat c(指向的就是new Cat())(猫类)放入形参中,此时的形参相当于:Cat c = new Cat();

    c.eat()方法调用猫类的eat方法,
    输出“猫吃鱼”。

    再加一个狗类型:
    和上面的一样,先创建一个狗类,再在操作类中添加一个新的useAnimal方法这次的形参类型是狗类,调用的是狗类的eat方法。

    运行:

    这样的方法明显比较麻烦,如果要创建多个动物就要重复上面的每一个步骤,
    所以我们运用多态。
    修改操作类:
    将useAnimal方法中的形参变为Animal(动物类),
    因为不管猫还是狗,它们都继承Animal(动物类),
    所以我们完全可以将Animal(动物类)作为形参。

    接着运行测试类:

    运行结果:

    运行结果和以前一样,解析:
    以Cat(猫)为例,
    ao.useAnimal©,
    调用ao(AnimalOperator)的useAnimal方法,
    useAnimal方法的形参类型是Animal(动物类),Cat(猫)类的父类也是Animal(动物类),
    所以完全可以将Cat c(指向new Cat())赋值给Animal(动物类),这样就变成了,Animal a = new Cat();

    这样就形成了多态,多态调用成员方法时,编译看左边,运行看右边,
    所以我们就是输出“猫吃鱼”
    这样利用多态就可以省去多个步骤,创建一个useAnimal方法即可。
    但是这样不可以调用子类的特有方法,因为编译看左边(父类)。

    1.4 多态中的转型

    代码示例:

    动物类:

    猫类:

    测试类:

    向上转型:
    父类引用指向子类对象,子类对象赋值给父类引用

    运行:

    但是通过向上转型的方法,访问不了子类特有的方法。

    所以要用到向下转型
    父类引用a转为子类对象Cat,赋值给Cat

    运行:

    1.5 多态转型内存图解

    从main方法开始执行,加载到栈内存

    Animal a加载到栈内存

    在堆内存中new一片空间(001),Cat继承了Animal,所以将地址001赋值给Animal a。

    这也叫向上转型

    多态中执行方法,编译看左边,执行看右边,将Cat类加载到栈内存中,调用eat方法,输出“猫吃鱼”。

    调用完毕后从栈内存消失

    执行Cat c = (Cat) a;,将Cat c加载到栈内存中

    a指向的是堆内存中的001,而001就是Cat,所以001完全可以赋值给Cat
    这就是向下转型

    c指向地址001(Cat),所以可以调用Cat中的方法。

    执行a = new Dog();,先在堆内存中new一片空间002,Dog也继承了Animal,所以也可以赋值给a,这时a的地址值变了002。

    执行a.eat():,调用方法执行看右边,进入Dog类执行eat()方法,输出“狗吃骨头”。
    方法执行结束从栈内存消失。

    Cat cc = (Cat) a;,将Cat cc加载到栈内存,(Cat) a,a的地址值是002,002对应的是Dog方法。

    虽然猫和狗都继承自Animal但是两者是没有任何关系的,所以他们相互之间是不能进行转换的。

    所以这个地方是错误的,如果强制执行就会报错,类型转换异常。

    1.6 使用多态的好处

     1.7 案例

    public class Animal {
        private String name;
        private int age;
    
        public void setName(String name){
            this.name=name;
        }
    
        public String getName(){
            return name;
        }
    
        public void setAge(int age){
            this.age = age;
        }
    
        public int getAge(){
            return age;
        }
    
        public Animal(){
            System.out.println("无参构造方法");
        }
    
        public Animal(String name, int age){
            System.out.println("有参构造方法");
        }
    
        public abstract void eat();
    }
    public class Cat extends Animal {
        public Cat(){
            super();
            System.out.println("猫子类无参构造方法");
        }
    
        public Cat(String name, int age){
            super(name, age);
            System.out.println("猫子类有参构造方法");
        }
    
        public void eat(){
            System.out.println("猫吃鱼");
        }
    }
    public class Dog extends Animal {
        public Dog(){
            System.out.println("狗子类无参构造方法");
        }
    
        public Dog(String name, int age){
            System.out.println("狗子类有参构造方法");
        }
    
        public void eat(){
            System.out.println("狗吃骨头");
        }
    }
    public class AnimalDemo {
        public static void main(String[] args) {
            Animal a = new Cat();
            a.eat();//猫吃鱼
    
            Animal b = new Dog();
            b.eat();//狗吃骨头
        }
    }
  • 相关阅读:
    jquery easy ui 学习 (8)basic treegrid
    jquery easy ui 学习 (7) TreeGrid Actions
    jquery easy ui 学习 (6) basic validatebox
    jquery easy ui 学习 (5) windowlayout
    jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性
    提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll
    visual studio 添加虚线的快捷键
    VS2010打开项目时,出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案
    visual studio 编译时 出现 Files 的值 乱码
    微信 连接被意外关闭
  • 原文地址:https://www.cnblogs.com/ajing2018/p/14665194.html
Copyright © 2011-2022 走看看