• Java的向上转型和向下转型


    一、向上转型(upcasting) 、向下转型(downcasting)

    举个例子:有2个类,Father 是父类,Son 类继承自 Father。

    第 1 个例子:

    Father f1 = new Son();   // 这就叫 upcasting (向上转型)
    // 现在 f1 引用指向一个Son对象
    
    Son s1 = (Son)f1;   // 这就叫 downcasting (向下转型)
    // 现在f1 还是指向 Son对象

    第 2 个例子:

    Father f2 = new Father();
    Son s2 = (Son)f2;       // 出错,子类引用不能指向父类对象

    你或许会问,第1个例子中:Son s1 = (Son)f1; 问为什么是正确的呢。

    很简单因为 f1 指向一个子类对象,Father f1 = new Son(); 子类 s1 引用当然可以指向子类对象  Son s1 = (Son)f1;

    而 f2 被传给了一个 Father 对象,Father f2 = new Father(); 子类 s2 引用不能指向父类对象 Son s2 = (Son)f2;

    总结:

    1、父类引用指向子类对象,而子类引用不能指向父类对象。

    2、把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转换吗,如:Father f1 = new Son();

      此时通过父类引用变量调用的方法是子类覆盖或继承 父类的方法,不是父类的方法。 

      此时通过父类引用变量无法调用子类特有的方法。

    3、把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转换,如:f1 就是一个指向子类对象的父类引用。把f1赋给子类引用 s1 即 Son s1 = (Son)f1;其中 f1 前面的(Son)必须加上,进行强制转换。

     
    参考:https://www.cnblogs.com/xiaoyezideboke/p/10939219.html

    二、向上转型的作用

    https://blog.csdn.net/guchenjun789/article/details/81055317 写的不错!!

    三、向上转型调用静态方法时的注意点

     比较下面代码输出结果(实际开发中不会遇到,只是在找工作时可能会遇到)

    非static方法

    public  class StaticTest
    {
        public static void main(String[] args)
        {
            Parent p = new Child();//向上转型
            p.output();
        }
    }
    
    class Parent
    {
        public  void output()
        {
            System.out.println("Parent");
        }
    }
    
    class Child extends Parent
    {
        public  void output()
        {
            System.out.println("Child");
        }
    }

    输出结果为:Child

    static方法

    public  class StaticTest
    {
        public static void main(String[] args)
        {
            Parent p = new Child();
            p.output();
        }
    }
    
    class Parent
    {
        public static void output()
        {
            System.out.println("Parent");
        }
    }
    
    class Child extends Parent
    {
        public static void output()
        {
            System.out.println("Child");
        }
    }

    输出结果为:Parent

    为什么加static修饰方法后结果就变不一样了呢? ???
    子类可以继承父类的静态方法,但是子类不能重写父类的静态方法。在这种情况下子类怎么办呢,子类隐藏(术语hidden)了父类的静态方法,因为子类没法重写,所以当p是Parent引用类型时,调用的就是Parent类里的output()方法,而不是Child类里的output()方法,因为Child类里没有重写output()方法,意思等价于Child类里根本没有父类版本的output()方法(Child里的output和Parent里的output方法是不同的方法,这样理解)

    如下代码可以证明子类没有重写父类静态方法(方法是加上@Override表示要重写,但是会编译报错)。

    public  class StaticTest
    {
        public static void main(String[] args)
        {
            Parent p = new Child();
            p.output();
        }
    }
    
    class Parent
    {
        public static void output()
        {
            System.out.println("Parent");
        }
    }
    
    class Child extends Parent
    {
        //加上注解后编译会报错,证明子类没有重写父类方法,若去掉static,编译不会报错
        @Override
        public static  void output()
        {
            System.out.println("Child");
        }
    }

    编译结果如下:

    StaticTest.java:20: 错误: 方法不会覆盖或实现超类型的方法
            @Override
            ^
    1 个错误

    四、向上转型中成员变量的调用

    第一个例子

    class A{
        int m;
        int getM(){
            System.out.printf("A中getM   ");
            return m;
        }
        int seeM(){
            System.out.printf("A中seeM   ");
            return m;
        }
        void setM(int m){
            this.m = m;
        }
    }
    
    class B extends A{
        int m;
        int getM(){
            System.out.printf("B中getM   ");
            return 100+m;
        }
        void setM(int m){
    
            this.m = m;
        }
        int seeM(){
            System.out.printf("B中seeM   ");
            return m+1;
        }
    }
    
    public class E{
        public static void main(String args[]){
            B b = new B();
            b.setM(20);
            b.m = 20;
            System.out.println(b.getM());//B中getM   120
            A a = b;
    
            a.setM(-50);//对B类的成员变量赋值,此时b.m=-50
            a.m = -100;//对A类的成员变量赋值!此时a.m=-100  注意和a.setM区别
            System.out.println(a.getM());//B中getM   50
            System.out.println(b.seeM());//B中seeM   -49
            System.out.println(a.m);
            System.out.println(b.m);
        }
    }

    如果B类不重写setM和getM方法,即:

    //class A{
    //    int m;
    //    int getM(){
    //        System.out.printf("A中getM   ");
    //        return m;
    //    }
    //    int seeM(){
    //        System.out.printf("A中seeM   ");
    //        return m;
    //    }
    //    void setM(int m){
    //        this.m = m;
    //    }
    //}
    //
    //class B extends A{
    //    int m;
    //    int getM(){
    //        System.out.printf("B中getM   ");
    //        return 100+m;
    //    }
    //    void setM(int m){
    //
    //        this.m = m;
    //    }
    //    int seeM(){
    //        System.out.printf("B中seeM   ");
    //        return m+1;
    //    }
    //}
    //
    //public class E{
    //    public static void main(String args[]){
    //        B b = new B();
    //        b.setM(20);
    //        b.m = 20;
    //        System.out.println(b.getM());//B中getM   120
    //        A a = b;
    //
    //        a.setM(-50);//对B类的成员变量赋值,此时b.m=-50
    //        a.m = -100;//对A类的成员变量赋值!此时a.m=-100  注意和a.setM区别
    //        System.out.println(a.getM());//B中getM   50
    //        System.out.println(b.seeM());//B中seeM   -49
    //        System.out.println(a.m);
    //        System.out.println(b.m);
    //    }
    //}
    class A{
        int m;
        int getM(){
            System.out.printf("A中getM   ");
            return m;
        }
        int seeM(){
            System.out.printf("A中seeM   ");
            return m;
        }
        void setM(int m){
            this.m = m;
        }
    }
    
    class B extends A{
        int m;
    
        int seeM(){
            System.out.printf("B中重写的seeM   ");
            return m+1;
        }
        int seeM2(){
            System.out.printf("B中新增的see2M   ");
            return super.m;
        }
    }
    
    public class E{
        public static void main(String args[]){
            B b = new B();
            b.setM(20);//设置A类的成员变量【隐藏变量】,setM方法未被重写,B类直接继承A类的setM方法
            System.out.println(b.m);//0!
            System.out.println(b.seeM());//1
            System.out.println(b.seeM2());//20
    
            A a = b;
            a.setM(-50);//设置A类的成员变量【隐藏变量】
            //a.m = -100;
            System.out.println(a.getM());//-50
            System.out.println(b.seeM());//1
            System.out.println(a.m);
            System.out.println(b.m);
        }
    }

    结论=》上转型对象通过重写的方法会调用继承的变量,通过“.”来直接访问隐藏的变量,未被重写的方法则会调用隐藏的变量

  • 相关阅读:
    mongoid和date_select的交道 小青年
    content_for对应的yield 小青年
    sunspot solr 小青年
    rails中validates及各种方法 小青年
    Rake: wrong number of arguments (3 for 2) 小青年
    nginx + nginxgridfs 安装方法 小青年
    gem install mysql2的时候出现的错误 小青年
    Rails Date Formats strftime 小青年
    redis 安装 小青年
    Uninstall all ruby gems 小青年
  • 原文地址:https://www.cnblogs.com/hemengjita/p/14056316.html
Copyright © 2020-2023  润新知