java-多态知识点总结

多态

  1. 定义

    同一个对象,在不同时刻表现出来的不同形态。(或者说父类的同一个方法在不同子类表现不同的结果,可以理解为表面声明为父类对象,但是真正调用的是那个new子类的方法。就是比如A是B,C的父类。A a1=new B();和A a2=new A():虽然这个a1和a2都是表现为表面是A但是你分别调用a1.f();和a2.f();的结果就不一样,就体现出不同的状态)

  2. 例子:

    我们可以说猫是猫:即,猫 cat=new 猫();

    也可以说猫是动物,即,动物 animal=new 猫();

  3. 多态的前提:

    • 两个类有继承或者实现的关系
    • 有方法重写
    • 有父类指向子类对象
  4. 多态中的成员访问特点

    • 成员变量

      ​ 编译看父类,运行看父类(编译看左边,执行看左边)

    • 成员方法

      ​ 编译看父类,运行看子类(编译看左边,执行看右边)

    例子:

    public class Animal {
        public int age = 40;
    
        public void eat() {
            System.out.println("动物吃东西");
        }
    }
    
    public class Cat extends Animal {
        public int age = 20;
        public int weight = 10;
    
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    
        public void playGame() {
            System.out.println("猫捉迷藏");
        }
    }
    
    public class AnimalDemo {
        public static void main(String[] args) {
            //有父类引用指向子类对象
            Animal a = new Cat();
    
            System.out.println(a.age);//输出40,体现多态的成员变量执行看左边。执行的效果看那个Animal a = new Cat();的左边,即看那个Animal类的age属性
    //        System.out.println(a.weight);//错误,体现多态的成员变量的编译看左边,这个编译不能通过
    
            a.eat();//输出"猫吃鱼"。体现多态的成员方法,执行看右边。执行的效果看那个Animal a = new Cat();的右边,即看那个Animal类的eat方法
    //        a.playGame();//错误,体现多态的成员方法,编译看左边,这个编译不能通过
        }
    }
    
  5. 多态的好处和弊端

    • 好处

      ​ 提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,可以传递这个父类对象或这个父类对象的子类对象。这样有什么好处呢?比如你要是不用多态的话,你一个工具类的一个方法只能处理一种类对象,比如你工具类里面有一个方法是

      public void f(A a){a.g();}
      

      那么这个工具类里的这个方法只能处理这个A这种对象f(new A()),但是你要是想传递一个B对象,你就只能再建一个方法。就算这两个方法的语句差不多,也要再建一个方法只是参数列表不同的方法,这样就很浪费时间,代码重复多。

      public void f(A a){a.g();}
      public void f(B b){b.g();}
      

      但是你要是在工具类里面定义一个这样的方法,然后ZIMU这个类是A,B,C……的父类,那么他们都可以用这一个方法来做事,不用重新定义一个方法了,而且这个zimu.g();的执行效果是看具体传入的对象的。

      public void f(ZIMU zimu){zimu.g();}
      
    • 弊端

      ​ 不能使用子类的特有成员

      ​ 比如还是用上面那个好处的那个例子:要是父类里只有g()没有h();方法,,但是A对象有这个他特有的父类没有的h()方法,那么你这样使用就会出错,因为编译看左边,即看ZIMU这个类(看对象表明的类型,即接受对象的那个引用的类型)。

      public void f(ZIMU zimu){zimu.h();}
      
  6. 多态中的转型

    转型可以解决多态的弊端。下面介绍转型。转型分为向上转型和向下转型两种。向上转型是自动的,向下转型的话要用“(要转为的类)”这个东西,具体看例子。

    • 向上转型

      ​ 父类引用指向子类对象就是向上转型,如,父类 对象名=new 子类();即父类接受子类都是向上转型。

    • 向下转型

      ​ 格式:子类型 对象名 = (子类型)父类引用;

      例子:

      public class Animal {
          public void eat() {
              System.out.println("动物吃东西");
          }
      }
      
      public class Cat extends Animal {
          @Override
          public void eat() {
              System.out.println("猫吃鱼");
          }
      
          public void playGame() {
              System.out.println("猫捉迷藏");
          }
      }
      
      public class AnimalDemo {
          public static void main(String[] args) {
              //多态
              Animal a = new Cat();//向上转型
              a.eat();//编译看左边,执行看右边
      //      a.playGame();//编译看左边,执行看右边
      
              Cat c = (Cat)a;//向下转型
              c.eat();
              c.playGame();//向下转型了,所以这个playGame方法就可以用了
          }
      }
      
    • 注意:向下转型可能是会出现问题的,比如你把一个Animal cat=new Cat(); Dog dog=(Dog)cat;会抛出异常。即把实体为Cat的对象转为别的类可能出现问题,能不能转得看那个实体能不能放进到那个强转的那个类里面。

  7. instanceof

    instance是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。

    instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回值为boolean型。

    比如,x instanceof A。(其中x是对象,A是类的名字)

    那么:

    • x是A这个类的子类的实例x是A这个类的实例都是返回true
    • x不是A这个类的子类实例也不是本类实例,都是返回false
    • x声明的时候表面上的类型和A这个类没有父子关系,那么编译不通过。就是编译看表面。执行看的是实际是否为他的子类或本类实例

    例子:

    package com.liudashuai;
    
    //x instanceof A:检验x是否为类A的对象,返回值为boolean型。
    //         要求x所属的类与类A必须是子类和父类的关系或本类,否则编译错误。
    //         如果x属于类A的子类B,x instanceof A值也为true。
    public class Demo4 extends HelloWorld{
        public static void main(String[] args) {
            Demo2 demo2=new Demo2();
            Demo1 demo1=new Demo1();
            Demo3 demo3=new Demo3();
            Demo4 demo4=new Demo4();
            Demo1 demo=new Demo3();
            System.out.println(demo1 instanceof Demo1);//true,本类实例instanceof本类
            System.out.println(demo1 instanceof Demo2);//false,父类实例instanceof子类
            System.out.println(demo3 instanceof Demo2);//true,子类实例instanceof父类,
            System.out.println(demo instanceof Demo2);//true,看实际的那个对象的类型判断true还是false。所以看实际的即“Demo3的实例 instanceof Demo2”是true,看表面的话,就是“Demo1的实例是不是Demo2”结果是false
    //        System.out.println(demo4 instanceof Demo2);//编译错误,因为这个demo4非Demo2这个类子类或父类或本类的实例。要求demo4表面所属的类与类Demo2必须是子类和父类的关系或本类,否则编译错误。=
            HelloWorld helloWorld=new Demo4();
            //表面是Demo2的父类(其实是子类的子类),实际上是Demo4,而Demo4和Demo2没有父子类关系,所以上面的demo4 instanceof Demo2编译错误是只看表面的
            System.out.println(helloWorld instanceof Demo2);//false
        }
    }
    
    package com.liudashuai;
    public class Demo3 extends Demo2{
    }
    
    package com.liudashuai;
    public class Demo2 extends Demo1{
    }
    
    package com.liudashuai;
    public class HelloWorld {
    }
    
    package com.liudashuai;
    public class Demo1 extends HelloWorld{
    }
    
    
    

    这几个类的父子关系是这样的:

    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值