zoukankan      html  css  js  c++  java
  • java基础---24. 多态性

    1 概述

    • 面向对象三大特征:封装性、继承性、多态性。其中,继承性是多态性的前提。

    • 继承性在java中的体现除了extends还有implements。所以extends继承和implements实现都是继承性的前提。

    • 不一定是类与类之间的继承,还有可能是接口与接口之间的继承,还有可能是类与接口之间的实现

    • 注意:多态性指的是对象而不是类

    2 多态的格式与使用

    代码当中体现多态性,其实就是一句话:父类引用指向子类对象。

    • 格式
    //方式1:
    父类名称 对象名 = new 子类名称();//子类对象就被当作父类进行使用,一只猫被当中动物来看待
    //或者
    //方式2
    接口名称 对象名 = new 实现类名称();
    
    对于方式1举例
    • 定义一个父类
    public class Fu {
        public void method(){
            System.out.println("父类方法");
        }
        public void methodFu() {
            System.out.println("父类特有方法");
        }
    }
    
    • 定义一个子类
    public class Zi extends Fu{
        @Override
        public void method() {
            System.out.println("子类方法");
        }
    }
    
    • 调用
    public class Demo01Multi {
        public static void main(String[] args) {
            //使用多态写法
            //左侧父类的引用指向右侧子类的对象
            Fu obj = new Zi();
            obj.method();//子类方法       对于成员方法,new的是谁就调用谁的方法 若没有就往上找
            obj.methodFu();//父类特有方法
        }
    }
    

    3 多态中成员变量的使用(规则不变)

    规则:访问成员变量两种方式

    • 1.直接通过对象名称访问成员变量(对象名称.变量名):看等号左边是谁,优先用谁,没有则向上找。
    • 2.间接通过成员方法访问成员变量:该方法属于谁则优先用谁,没有则向上找。
      注意:成员变量不可以覆盖重写,只有方法可以覆盖重写
    举例
    • 定义一个父类
    public class Fu {
        int num = 10;
        public void showNum(){
            System.out.println(num);
        }
    }
    
    • 定义一个子类
    public class Zi extends Fu {
        int num = 20;
        int age = 18;
    }
    
    • 使用
    public class Demo01MutilField {
        public static void main(String[] args) {
            //使用多态写法,父类引用指向子类对象
            Fu obj = new Zi();//等号左边是Fu
    
            //1.
            System.out.println(obj.num);//10
            //System.out.println(obj.age);//错误写法,Fu中没有age,再向上找是Oject类也不会有age
    
            //2.
            obj.showNum();//10   子类没有对该方法覆盖重写则就向上找父输出10;若子类对该方法覆盖重写那就是子输出20
    
        }
    }
    

    4 多态中成员方法的使用(规则不变)

    规则:看new的是谁,就优先用谁,没有则向上找
    口诀:编译看左边,运行看右边
    对于成员变量的口诀:编译看左边,运行还看左边

    举例
    • 定义一个父类
    public class Fu {
        public void method(){
            System.out.println("父类方法");
        }
        public void methodFu(){
            System.out.println("父类特有方法");
        }
    }
    
    • 定义一个子类
    public class Zi extends Fu {
        @Override
        public void method(){
            System.out.println("子类方法");
        }
    
        public void methodZi(){
            System.out.println("子类特有方法");
        }
    }
    
    • 使用
    public class Demo02MutilMethod {
        public static void main(String[] args) {
            Fu obj = new Zi();//多态
            obj.method();//子类方法
            obj.methodFu();//父类特有方法    子类没有改方法,所以向上找到了父类的该方法
    
            //obj.methodZi();//错误写法
            //编译看左边,左边是Fu,而Fu当中没有methodZi方法,所以出现红线,编译报错
        }
    }
    

    5 多态的好处

    调用方法的时候,编译看左边,运行看右边

    6 对象的向上转型

    举例

    本例用的是类当然也可以用接口

    • 定义一个Animal类
    public abstract class Animal {
        public abstract void eat();
    }
    
    • 定义一个Cat类
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    
    • 使用
    public class Demo01Main {
        public static void main(String[] args) {
            //对象的向上转型就是:父类引用指向子类对象
            Animal animal = new Cat();
            animal.eat();//猫吃鱼
            //编译看左:左边Animal有eat方法
            //运行看右:运行右边Cat的eat方法
        }
    }
    
    举例(接口)
    • 定义一个接口
    public interface Animal {
        public abstract void eat();
    }
    
    • 定义一个实现类
    public class Cat implements Animal{
        @Override
        public void eat() {
            System.out.println("猫爱吃鱼鱼");
        }
    }
    
    • 使用
    public class Demo01Main {
        public static void main(String[] args) {
            Animal animal = new Cat();
            animal.eat();//猫爱吃鱼鱼
        }
    }
    

    7 对象的向下转型

    问题引入

    向上转型是安全的,没有问题。但是有弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

    • 父类
    public abstract class Animal {
        public abstract void eat();
    }
    
    • 子类
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    
        //子类特有方法
        public void catchMouse(){
            System.out.println("猫抓老鼠");
        }
    }
    
    • 使用
    public class Demo01Main {
        public static void main(String[] args) {
            //对象的向上转型就是:父类引用指向子类对象
            Animal animal = new Cat();
            animal.eat();//猫吃鱼
            //编译看左:左边Animal有eat方法
            //运行看右:运行右边Cat的eat方法
    
            //animal.catchMouse();//错误写法  编译报错  Animal中没有这个方法  并不是所有的动物都会猫抓老鼠
        }
    }
    
    解决方案:向下转型【还原】

    向上转型一定安全,向下转型有前提条件

    • 父类
    public abstract class Animal {
        public abstract void eat();
    }
    
    • 子类Cat
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    
        //子类特有方法
        public void catchMouse(){
            System.out.println("猫抓老鼠");
        }
    }
    
    • 子类Dog
    public class Dog extends Animal{
        @Override
        public void eat(){
            System.out.println("狗吃骨头");
        }
    
        public void watchHouse(){
            System.out.println("狗狗看家");
        }
    }
    
    • 使用
    public class Demo01Main {
        public static void main(String[] args) {
            //对象的向上转型就是:父类引用指向子类对象
            Animal animal = new Cat();//本来创建的时候是一只猫
            animal.eat();//猫吃鱼
    
    
            //animal.catchMouse();//错误写法  编译报错  Animal中没有这个方法  并不是所有的动物都会猫抓老鼠
    
            //向下转型进行还原动作
            Cat cat = (Cat)animal;
            cat.catchMouse();//猫抓老鼠
    
            //错误的向下转型
            //本来new的时候是一只猫,现在非要当作狗狗
            Dog dog = (Dog)animal;//编译不报错,但是运行异常:java.lang.ClassCastException类转换异常
        }
    }
    
    新的问题:如果知道父类的引入本来是Cat还是Dog呢?
    • 格式
    对象 instanceof 类名称
    

    这将会得到一个boolean值结果,也就是判断前面的对象能不能当作后面类型的实例。

    public class Demo02Instanceof {
        public static void main(String[] args) {
            Animal animal = new Cat();//本来就是一只猫
            animal.eat();//猫吃鱼
            giveMePet(new Cat());
        }
        
        public static void giveMePet(Animal animal){
            //如果希望用子类特有方法,需要向下转型
            //判断传入的参数本来是猫还是狗,再决实施行何种向下转型的方案
            if(animal instanceof Dog) {//判断一下父类引用animal本来是不是狗
                Dog dog = (Dog)animal;
                dog.watchHouse();
            }
            if(animal instanceof Cat){//判断一下父类引用animal本来是不是猫
                Cat cat = (Cat)animal;//猫抓老鼠
                cat.catchMouse();
            }
        }
    }
    
  • 相关阅读:
    55.UIbutton点击切换颜色
    54.NSJSONSerialization类进行json解析(字符串“UTF-8解码”)
    53.设置内容的行间距
    第二阶段冲刺7
    第二阶段冲刺6
    第十四周
    第二阶段冲刺5
    第二阶段冲刺4
    第二阶段冲刺3
    第二阶段冲刺2
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12247799.html
Copyright © 2011-2022 走看看