全面讲解⾯向对象编程三⼤特性 2

电子说

1.2w人已加入

描述

我们来看上面part1部分:

Cat cat_ = new Cat();
        cat_.eat();
        cat_.sleep();
        cat_.work();

结果:

吃鱼

猫会睡懒觉。

动物可以帮助人类干活!

cat_.work(); 这处继承了父类Animal的方法,还是很好理解的

我们接着看part2:

Animal cat=new Cat();
        cat.eat();
        cat.work();
        cat.sleep();//此处编译会报错。

        Animal dog=new Dog();
        dog.eat();//结果为:吃骨头。此处调用子类的同名方法。

这块就比较特殊了,我们一句句来看

Animal cat=new Cat(); 像这种这个 父类引用指向子类对象,这种现象叫做: "向上转型" ,也被称为 多态的引用

cat.sleep();这句 编译器会提示 编译报错。表明:当我们当子类的对象作为父类的引用使用时,只能访问子类中和父类中都有的方法,而无法去访问子类中特有的方法

值得注意的是:向上转型是安全的。但是缺点是:一旦向上转型,子类会丢失子类的扩展方法,其实就是 子类中原本特有的方法就不能再被调用了。所以cat.sleep()这句会编译报错。

cat.eat();这句的结果打印:吃鱼。程序这块调用我们Cat定义的方法。

cat.work();这句的结果打印:动物可以帮助人类干活!我们上面Cat类没有定义work方法,但是却使用了父类的方法,这是不是很神奇。其实此处调的是父类的同名方法

Animal dog=new Dog();dog.eat();这句的结果打印为:吃骨头。此处调用子类的同名方法。

由此我们可以知道当发生向上转型,去调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。如果子类没有同名方法,会再次去调父类中的该方法

编译器

向上转型

我们现在知道了 向上转型时会丢失子类的扩展方法,哎,但我们就是想找回来,这可咋办?

向下转型可以帮助我们,找回曾经失去的

我们来看part3:

Cat cat_real = (Cat)cat;  //注意 此处的cat 对应上面父类Animal,可不是子类
    cat_real.sleep();

Cat cat = (Cat)cat; cat222.sleep(); 这个向下转型非常像"强转"。

打印的结果:猫会睡懒觉。此处又能调用了 子类Cat 的 sleep()方法了。

一道简单的面试题

我们再来看一道有意思的题,来强化理解

public class Main {
    
    static class Animal{
        int weight = 10;

        public void print() {
            System.out.println("this Animal Print:" + weight);
        }

        public Animal() {
            print();
        }
    }

    static class Dog extends Animal {
        int weight = 20;

        @Override
        public void print() {
            System.out.println("this Dog Print:" + weight);
        }

        public Dog() {
            print();
        }
    }

    public static void main(String[] args) {
        Dog dog = new Dog();

        System.out.println("---------------");
        Animal dog222 = new Dog();
        Dog dog333 =  (Dog)dog222;
        
        System.out.println("---------------");
        Dog dog444 = (Dog)new Animal();

    }
}

执行结果:

this Dog Print:0
this Dog Print:20
---------------
this Dog Print:0
this Dog Print:20
---------------
this Animal Print:10
Exception in thread "main" java.lang.ClassCastException: com.zj.Main$Animal cannot be cast to com.zj.Main$Dog
 at com.zj.Main.main(Main.java:15)

做对了嘛,不对的话,复制代码去idea中debug看看

我们先看第一部分

Dog dog = new Dog();

程序内部的执行顺序:

  1. 先 初始化 父类Animal 的属性 int weight=10
  2. 然后 调用父类Animal的构造方法,执行print()
  3. 实际调用子类Dog的print()方法,打印:this Dog Print:0,由于此时的子类属性weight 并未初始化
  4. 初始化 子类Dog 的属性 int weight=20
  5. 调用 子类Dog的构造方法,执行print()
  6. 实际调用当前类的print()方法,打印this Dog Print:20

其中有几处我们需要注意一下:实例化子类dog,程序会去默认优先实例化父类,即子类实例化时会隐式传递Dog的this调用父类构造器进行初始化工作,这个和JVM的双亲委派机制有关,这里就不展开讲了,先挖个坑,以后再来填

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分