FJ--多态的动态绑定

*多态的概述

public class Demo9_Polymorphic {
      public static void main(String[] args) {
      /*
      Cat a = new Cat();
      a.eat();
      a.catchMouse();
      
      Dog d = new Dog();
      d.eat();
      d.lookHome();
 
      */
      /*
      Animal a = new Dog();
      a.eat();
      //a.catchMouse();
      
      Animal a2 = new Dog();
      a2.eat();
      */
      
      method(new Dog());
      method(new Dog());
      
      
      }
      public static void method(Cat cc) {
      cc.eat();
    }
}
class Animal {
      public void eat() {
             System.out.println("动物吃");
      }
}

class Cat extends Animal{
      public void eat() {
              System.out.println("鱼");
      }
      public void catchMouse() {
              System.out.println("抓老鼠");
      }
}

class Dog extends Animal{
      public void eat() {
              System.out.println("肉");
      }
      public void lookHome() {
              System.out.println("看家");
      }
}

 1.动态绑定:是指"在执行期间"(而非编译期间)判断所引用对象的实际类型,根据实际类型调用相应的方法

    下面就用内存图解释这一点:先看上面代码,再看内存图

1.1 Animal a = new Cat(); 指的是:父类类型的引用指向子类对象. 当代码执行到这一句时,父类会先进内存(这就是前面学到的用到就要加载到内存),然后子类也就是Cat类也加载进入内存.

1.2 子类从父类继承来的成员变量(属性)全都是存在隐藏的super内存里面(其实我觉得继承来的方法,以地址的形式也存在在这里面--冯佳没讲方法).剩余其他部分也就是属于this了.

1.3 Animal a 只能看到super里面的,也就是父类里面的,而看不到this里面的东西.重点来了,编译的时候会先看看父类的eat()方法,为什么呢???因为a是Animal类型的,所以编译的时候super下面的那个线会指向Animal类里的eat方法.在运行的时候这个时候就是动态绑定了他会指向子类Cat里面,看看子类有没有重写eat方法,如果子类里面没有重写eat方法就执行父类里面的eat方法,如果子类里面重写了eat方法就执行子类里面的eat方法.

1.4 怎么验证1.3的说法呢?把父类里面的eat方法给去掉,立马就会报错(这种错误属于编译错误)说找不到符号.--冯佳

1.5 解释(1.动态绑定):所引用对象的实际类型是什么?我们是用那个类创建的对象,是Cat类.所以实际类型就是Cat类,所以动态绑定执行的时候就会去Cat类里面去eat方法.

1.6 根据这个图:编译看左边运行看右边.(针对方法)--冯佳

1.7 编译看左边,运行也看左边(针对变量.代码重叠)--佳庆

     编译看左边父类:如果父类没有这个变量,编译时期,语法报错

     运行也看左边父类:运行时,真正执行的是父类的变量

2.多态的好处和弊端

  1.7问题: 能不能执行a.catchMouse();方法呢? 答:不能. 为什么?因为父类里面没有编译就通不过.

  1.8问题: 父类的引用指向子类对象这样创建对象,子类的特有方法就没办法执行了就如下面代码:

Animal a = new Cat();
a.eat();

Animal a2 = new Dag();
a2.eat();

   要通过这种方式去调用eat()方法太麻烦了--->>所以就再创建一个方法.--->>在方法里调用eat();

public static void method(Cat cc) {
 cc.eat();
}

   怎么去调用method方法呢?下面这样调用

method(new Cat());
//就相当于 Cat cc = new Cat();
//这样就可以调用eat()方法了

但是method(new Dog());又不行了

  method(new Dog());又不行了,问题还是没有解决啊?还是没有简便啊?

   所以把括号里面的Cat改成Animal问题就解决了.

public static void method(Animal cc) {
 cc.eat();
} 

   现在下面的代码全部都可以执行了,这就是多态的好处,提高了代码的扩展性.

method(new Cat());
method(new Dog());

总结1:多态的需要具备的3个条件

  1. 父类引用指向子类对象

  2. 要有继承(类)或者实现(接口)

  3. 要有重写

总结2:好处和弊端

    1. 多态的好处,提高代码的扩展性
    2. 多态的弊端,不能调用子类的特有方法

3.向上转型和向下转型

public class Demo9_Polymorphic {
      public static void main(String[] args) {
             Animal a = new Cat();//这叫向上转型
             a.eat();
             
             Cat c = (Cat)a;//这叫向下转型
             c.catchMouse();
      }
      
}
}
class Animal {
      public void eat() {
             System.out.println("动物吃");
      }
}

class Cat extends Animal{
      public void eat() {
              System.out.println("鱼");
      }
      public void catchMouse() {
              System.out.println("抓老鼠");
      }
}

class Dog extends Animal{
      public void eat() {
              System.out.println("肉");
      }
      public void lookHome() {
              System.out.println("看家");
      }
} 

 

 

Cat c = (Cat)a;//这叫向下转型

解释:这句代码并没有创建对象,而是把0*0022地址给了c.所以c也就指向了整个对象,也可以说this所在的内存.其实super里面的也可以调用,全部都可以我自己试了.

重点:再说一遍a只能指向super所在的内存.

总结:

  1. 多态自始至终都是子类对象在做着变化

  2. 为了让大家更加清晰地了解多态,举例超人的例子

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值