正在回答
我是这样认为的:
你这个代码拆解一下,首先是Animal one;声明了一个Animal类型的引用对吧?然后由new Roo();创建了一个Roo类型的对象,在内存的堆中开辟了该对象的存储空间,然后将该对象存储空间返回,于是有one = new Roo();也就是说子类Roo的一个新创建的对象的首地址被返回给了父类Animal类型的引用,one就是这个首地址的别名,直接可以用来操作从这个地址开始的存储这个对象的这块内存空间,也即是可以通过one用来使用这个对象。
好了,此时呢,one被编译器视作是Animal类的对象,但实际上它指向的是Roo类的对象,而父类引用是可以向下兼容子类的,因为父类有的子类全都继承了,可以正常调用(父类私有的除外,另外重写的方法除外,后面说),但子类有的(扩展的),父类不一定有,所以子类引用不可以向上兼容父类。回到父类引用one上,那么既然编译器认为one是父类的引用,因此,使用one这个引用你只能调用到父类对象和子类对象所共有的在访问限制符允许访问的范围内的属性和方法。至于在子类中的方法,Java中的方法其实是存储在堆中一块单独的叫做方法区的内存区域,这个区域并不是为某个对象所独有,而是一块公共区域,也就是说不管你是哪个类的方法(同一类不同对象之间方法都是一样的,所以方法是按类来存储而不是像属性那样按对象存储在堆中)都会扔进这个池子一样的大杂烩区域存储起来。one作为一个父类引用,当他去调用他所创建的子类对象所重写的方法时编译器其实是根据引用类型来判断然后去方法区来找对应引用类型对象的方法的,也就是说调用的其实还是父类的方法而不是子类重写的方法。
最后回到你的第二句代码((Roo)one).leap();这句代码中的(Roo)one其实就是告诉编译器,在处理这条代码时把Animal类型引用one当做一个Roo类型引用来看待,上面已经解释过了父类的引用是可以向下兼容子类的,所以这句话可以通过编译,编译器自然就会把one当成是Roo类型的引用再来执行操作,而此时以这种方式再调用leap()方法,编译器就知道这是Roo类型的leap方法,然后去方法区找到Roo对应的leap()方法的代码然后执行。
这么讲你能明白吗?
Animal one = new Roo(); ((Roo)one).leap();
这段断码是否这样理解:
Animal one = new Roo();
Animal one 创建了一个Animal类的引用变量one,new Roo() 创建了一个Roo类的对象。在Animal one = new Roo() 这个操作中,将堆中的Roo对象(能否成为Roo类的实例?)向上转成了Roo父类的Animal类的对象,然后用Animal的引用变量one指向了此时被转换成了Animal对象的原Roo对象。
((Roo)one).leap();
将Animal类的引用变量one指向的Animal对象强制转换成Roo对象,然后调用Roo对象中的leap方法
- 参与学习 人
- 提交作业 7317 份
- 解答问题 14452 个
想要入门学编程?多年一直活跃在编程语言排行版前列的Java是一个很好的选择。本路径将从Java基础语法、面向对象、常用工具类三部分,为你开启软件开发的大门!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星