我们来看上面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();
程序内部的执行顺序:
- 先 初始化 父类Animal 的属性 int weight=10
- 然后 调用父类Animal的构造方法,执行print()
- 实际调用子类Dog的print()方法,打印:
this Dog Print:0
,由于此时的子类属性weight 并未初始化 - 初始化 子类Dog 的属性 int weight=20
- 调用 子类Dog的构造方法,执行print()
- 实际调用当前类的print()方法,打印
this Dog Print:20
其中有几处我们需要注意一下:实例化子类dog,程序会去默认优先实例化父类,即子类实例化时会隐式传递Dog的this调用父类构造器进行初始化工作
,这个和JVM的双亲委派机制有关,这里就不展开讲了,先挖个坑,以后再来填
-
编译器
+关注
关注
1文章
1623浏览量
49104 -
面向对象编程
+关注
关注
0文章
22浏览量
1811
发布评论请先 登录
相关推荐
评论