美文网首页
JAVA:向上转型和动态绑定机制

JAVA:向上转型和动态绑定机制

作者: 确认过眼神啊 | 来源:发表于2020-09-11 09:31 被阅读0次

    知识梳理

    1.向上转型的概念:
    向上转型又叫自动转型、隐式转型.向上转型就是父类引用指向子类实例,也就是子类的对象可以赋值给父类的对象.

    Animal dog = new Dog(); // Dog类是Animal类的子类
    

    注:向上转型是安全的,因为任何子类都继承并接受了父类的方法.从例子中也可以理解,所有的狗都属于狗的父类-动物,这是可行的,但是向下转型则不行,若说所有的动物都是狗就不成立.(所以向下转型要通过强制类型转换,后续章节中会将解)
     
    2.向上转型的应用
    1)当一个子类对象向上转型父类类型以后,就被当成了父类对象,所能调用的方法会减少,只能调用子类重写了父类的方法以及父类派生的方法(如set(),get()方法),而不能调用子类特有的方法.

    public class Animal{
       String name;
       int age;
       public Animal(){
        
       }
       public void eat(){
         System.out.println("animal吃东西");
       }
    
        public static void die(){
                System.out.println("animal死亡");
            }
    }
    public class Dog extends Animal{
          String favoriteFood;
           public void eat(){
               System.out.println("吃肉");
            }
            public void run(){
                System.out.println("夕阳下奔跑的小狗");
            }
            public static void die(){
                System.out.println("dog死亡");
            }
     }
    public static void main(String[] args){
        Animal animal = new Dog();
        animal.age = 2;
        animal.name = "小强";
        animal.favoriteFood = "骨头"; // 访问子类的属性报错
        animal.eat(); // 调用的是子类的方法,输出结果是"吃肉"
        animal.run();// 访问子类特有的方法报错
        animal.die();// 调用的是父类的方法,输出结果是"animal死亡"
    }
    

    2)父类中的静态方法时不允许被子类重写的
    如父类的有静态方法die()
    当子类Dog中也定义同名方法时,此时die()算dog类自己独有的方法:

      Animal animal = new Dog(); // 向上转型
      animal.die();// 调用的是Animal类的die()方法,而不是调用Dog的die()方法
     // 输出结果是:animal死亡
    

    知识扩展

      多态的实现可以通过向上转型和动态绑定机制来完成,向上转型实现了将子类对象向上转型为父类类型,而动态绑定机制能识别出对象转型前的类型,从而自动调用该类的方法,两者相辅相成.
    动态绑定:
    绑定就是讲一个方法调用同一个方法所在的类连接到一起就是绑定.绑定分为静态绑定和动态绑定两种.

    • 静态绑定:在程序运行之前进行绑定(由编译器和链接程序完成的),也叫做前期绑定.
    • 动态绑定:在程序运行期间由JVM根据对象的类型自动判断应该调用哪个方法,也叫做后期绑定.
      静态绑定的例子:
        如有一类Human,它派生出来三个子类Chines类,American类和British类,三个子类中都重写了父类中的方法speak():void,在测试类中用静态绑定的方式调用方法speak().
      Chinese c = new Chinese();
      c.speak();
      American a = new American();
      a.speak();
      British b = new British();
      b.speak();
    

    这种调用方式是在代码里指定的,编译时编译器就知道c调用的是Chinese的speak(),a调用的是American的speak().
    动态绑定的例子:
    如果我们在测试类中做以下改动:

    // 生成父类对象数组,数组长度为5
    Human[] human = new Human[5];
    int n;
    for(int i = 0; i < human.length;i++){
      n = (int)(Math.random() * 3); // 随机产生从0到2中的一个数
      switch(n){
        case 0: human[i] = new Chinese();break;
        case 1: human[i] = new American();break;
        case 2: human[i] = new British();break;
      }
    }
    // 循环输出,循环体中每个对象分别调用speak()方法
    for(int i = 0;i < human.length;i ++){
      human[i].speak();
    }
    

    此时,Human类中随机生成Chinese类,American类和British类的对象,编译器不能根据代码直接确定调用那个类中的speak()方法,知道运行时才能根据产生的随机数n的值来确定human[i]到底代表哪一个子类的对象,这样才能最终确定调用的是那个类的speak()方法,这就是动态绑定.

    相关文章

      网友评论

          本文标题:JAVA:向上转型和动态绑定机制

          本文链接:https://www.haomeiwen.com/subject/fymdektx.html