• Java SE之向上转型(动态绑定)与向下转型


    【Keywords】:向上转型 向下转型 动态绑定[1] 静态绑定
    【Abstract】:Java调用对象方法时,一般采用运行时绑定机制。[1]
             在程序运行时,采用动态绑定意味着:虚拟机将调用对象实际类型所限定的方法。
             向上转型要点:
               1.定义父类对象指向子类对象。
               2.理解动态绑定。
               3.转型后的父类实例仅可以调用子类继承父类的方法和属性;
               4.转型后的父类实例优先调用子类继承的方法,其次优先调用父类固有方法。                  
             向下转型要点:
               1.向下转型建立在向上转型的基础上[否则:转型不安全]
               2.向下转型时必须进行强制转换。
               3.父类对象(即被转型实例)强制转换类型必须与转型后的实例类型相同。[见示例5]  

    两种转型区别:

       若想操作拥有共同父类的不同(子)类们的实例,就向上转型;

       若想当成指定的具体的子类的实例,就向下转型。

       越向上,概念越模糊,可以代表多种不同的类的实例,

       越向下,概念越具体详细,可以代表特定的类的实例。 
     

    向上转型

    1.定义:子类到父类的转换通常称作向上转型,通俗的说就是定义父类对象指向子类对象。
         
    public class Father {  
      public void method() {  
        System.out.println("父类方法,对象类型:" + this.getClass());  
      }  
    }  
        
    public class Son extends Father {  
      public static void main(String[] args) {  
        Father sample = new Son();//向上转型  
        sample.method();  
      }  
    }  
    

    结果1:

      父类方法,对象类型:class samples.Son

      这个结果没有疑问,声明的是父类的引用(句柄),但准确的调用了子类的对象,调用method,在子类中没有该方法,所以去父类中寻找到并调用之。  
          
    2.Question:子类对象向上转型为父类实例后,调用的是父类方法,还是子类方法?

       Answer:    

          当子类重写了父类方法,向上造成后调用的是子类方法

                  子类没有重写父类方法,向上转型后调用的是父类方法。
    示例2:

    package test;  
      
    public class HelloWorld {  
        public static void main(String[] args)  {  
            A k=new B();  
            k.sayHi();  
            k.hello();  
        }     
        }  
    class A {  
        public void sayHi(){  
            System.out.println("我是父类");  
        }  
        public void hello(){  
            System.out.println("我是父类hello");  
        }  
    }  
    class B extends A{  
        public void sayHi(){  
            System.out.println("我是子类");  
        }  
    }  
    

    输出结果:

    我是子类
    我是父类hello

    示例3:

    package test;  
    class Animal {  
          
        public void eat(){  
            System.out.println("animal eatting...");  
        }  
    }  
    class Bird extends Animal{  
          
        public void eat(){  
            System.out.println("bird eatting...");  
        }  
          
        public void fly(){  
              
            System.out.println("bird flying...");  
        }  
    }  
    public class HelloWorld{  
          
        public static void main(String[] args) {  
              
            Animal b=new Bird(); //向上转型  
            b.eat();   
              
            //! error: b.fly(); b虽指向子类对象,但此时丢失fly()方法  
              
            /*b实际指向的是Bird子类,故调用时会调用子类本身的方法。 
     
            需要注意的是向上转型时b会遗失除与父类对象共有的其他方法。如本例中的fly方法不再为b所有。*/  
              
        }  
      
    }  
    

     

     

    向下转型 

    向下转型:将一个指向子类对象的父类引用赋给一个子类的引用,称为向下转型。注意:必须进行强制类型转换。

    (应用目标场景):上面已经说到,当向上转型发生后,将无法调用子类特有的方法。但是当需要调用子类特有的方法时,可以通过将父类在转换为子类来实现。

    要点:
      1.向下转型建立在向上转型的基础上[否则:转型不安全]
      2.向下转型时必须进行强制转换。
      3.父类对象(即被转型实例)强制转换类型必须与转型后的实例类型相同。[见示例5]
       

    详解:

    1.正确的向下转型    

                       Fruit a=new Apple(); //向上转型
                        a.myName(); 
                        Apple aa=(Apple)a; //向下转型,编译和运行皆不会出错(正确的)
                        aa.myName();
                        aa.myMore();

    a指向子类的对象,所以子类的实例aa也可以指向a啊~~

    向下转型后因为都是指向子类对象,所以调用的当然全是子类的方法~~

    2.不安全的向下转型

                   Fruit f=new Fruit();
                   Apple aaa=(Apple)f; //-不安全的---向下转型,编译无错但会运行会出错
                   aaa.myName();
                   aaa.myMore(); 

    f是父类对象,子类的实例aaa肯定不能指向父类f啊~~~

    3.Java为了解决不安全的向下转型问题,引入泛型的概念
     

    示例4:

    [java] view plain copy
    package com.sheepmu;  
     class Fruit  
      {  
        public void myName()  
        {  
            System.out.println("我是父类  水果...");  
        }  
    }  
       
    class Apple extends Fruit  
    {   
        @Override  
        public void myName()   
        {   
            System.out.println("我是子类  苹果...");  
        }  
        public void myMore()  
        {  
            System.out.println("我是你的小呀小苹果~~~~~~");  
        }  
    }  
      
    public class Sys{   
        public static void main(String[] args) {   
            Fruit a=new Apple(); //向上转型  
            a.myName();  
              
            Apple aa=(Apple)a; //向下转型,编译和运行皆不会出错(正确的)  
            aa.myName();//向下转型时调用的是子类的  
            aa.myMore();;  
                
            Fruit f=new Fruit();  
            Apple aaa=(Apple)f; //-不安全的---向下转型,编译无错但会运行会出错  
            aaa.myName();  
            aaa.myMore();   
        }  
    }  
    

    输出:

    我是子类  苹果...
    我是子类  苹果...
    我是你的小呀小苹果~~~~~~
    Exception in thread "main" java.lang.ClassCastException: com.sheepmu.Fruit cannot be cast to com.sheepmu.Apple
    at com.sheepmu.Sys.main(Sys.java:30)

    示例5:

    public class Test{ 
       Animal animal=new Dog(); 
       Dog dog=(Dog)animal;//向下转型,强制转换为狗狗对象 
       Cat cat=(Cat)animal;//运行出错
    }

    注解:

    [1]运行时绑定也叫动态绑定,它是一种调用对象方法的机制。Java调用对象方法时,一般采用运行时绑定机制。

      1.Java的方法调用过程

      编译器查看对象的声明类型和方法名(对象变量的声明类型)。通过声明类型找到方法列表。

      编译器查看调用方法时提供的参数类型。

      如果方法是private、static、final或者构造器,编译器就可以确定调用那个方法。这是静态绑定。

      如果不是上述情况,就要使用运行时(动态)绑定。在程序运行时,采用动态绑定意味着:虚拟机将调用对象实际类型所限定的方法。

      2.运行时(动态)绑定的过程

      虚拟机提取对象的实际类型的方法表;

      虚拟机搜索方法签名;

      调用方法。

      注意,这里说的是对象的实际类型。即在多态的情况下,虚拟机可以找到所运行对象的真正类型。

    参考文档:

    Java面向对象向上转型和向下转型有什么区别?

    1.【java】向上转型和向下转型:http://blog.csdn.net/lzm18064126848/article/details/47953203

    2.【java】深入向上转型(动态绑定) :http://blog.csdn.net/lzm18064126848/article/details/53872332

    3.Java向上转型和向下转型(附详细例子):http://blog.csdn.net/sheepmu/article/details/38327205
    4.Java中的向上转型和向下转型: http://www.cnblogs.com/heyongjun1997/p/5409230.html

  • 相关阅读:
    HashMap的负载因子为什么默认是0.75?这篇文章告诉你答案
    如何设计短网址系统?
    前端HTML史上最全总结,入门级边学边实战!
    阿里2021最全新的java面试题总结
    三万字,100题!Linux知识汇总!
    程序员路线图
    基于nodejs的selenium的自动化测试之网络元素
    Electron桌面程序入门研究
    Git常用命令
    二次探测法
  • 原文地址:https://www.cnblogs.com/johnnyzen/p/7155319.html
Copyright © 2020-2023  润新知