《零基础学 Java》 FAQ 之 12- 理解引用
引用是什么
@梁大瓜 在 “76 | 多态里更多的语法点(上)” 里说到
老师我这样理解不知道对不对:声明引用实际上就是在堆中建立里一块引用类的内存地址指向,
这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域中放入子类覆盖了与父类相同方法的值。
所以在调用的时候,返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。
回答
声明引用实际上就是在“内存”(可以是堆,比如是一个成员变量,也可以是线程栈,比如说说一个局部变量或者参数)中建立里一块(32bit或者64bit大小)引用“对象”的内存地址指向,这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域(32bit或者64bit大小,和对象类型以及大小没关系,只是一个地址)中放入“子类或者本类的对象的地址”。所以在调用(调用什么?方法吗?)的时候,(后面感觉有点模糊,你可以再说的清楚一点)返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。
其实覆盖不复杂,核心就是:寻找调用哪个方法。这里有两个角色:
引用的类型,调用的方法签名必须是这个类型中定义了的;
引用实际指向的对象,它决定的是通过这个签名调用的实际是哪个类的方法。
结合super,this,重载,问题会变得复杂,但是万变不离其宗,也就是上面的亮点。
以下内容涉及堆和栈
至于底层的逻辑,你的描述中有一个可能的错误,就是认为引用是在堆里建立一块内存。其实引用就是在内存里建立一个引用。也就是我们说的对象的“名”。
这里说的内存,可能是栈上的,比如下面的代码:
public void test(){
Person person = new Person();
}
person是个局部变量,那就是在栈内存上。
Person类的定义如果如下的话:
public class Person{
private Company company = null;
}
那么company这个引用就是在堆上。因为整个Person对象都在在堆上分配的内存,所有对象都是在堆上分配的内存。只有执行方法的时候,需要的局部变量和参数,才是在栈上分配内存。
父类引用指向子类对象有什么作用/不同
还是 @梁大瓜 同学,在“75 | 多态:到底调用的哪个方法?(下)” 问到
但是这样的话为什么Java还允许父类的引用可以指向子类的对象呢?既然不管引用是啥,
最后在执行的时候this指针指向的都是对象实际上引用的类,这个存在的意义是啥呢?
我之前自己学Java面向对象的时候就是在这个地方被搞的很晕。
梁大瓜同学两分钟之后自己就悟到了。问题是个好问题。有时候问问题的时候,自己就想通了。
回答
在这里我再总结一下这三个模式。
父类引用指向子类对象,可以调用只在父类中的方法(继承)
父类引用指向子类对象,可以调用子类覆盖了父类的方法(覆盖,多态)
父类引用指向子类对象,在1)和2)这两种情况下。如果这个方法的代码中又调用了别的方法,那么还是会遵循这个规则。举个例子,如果父类中有m1,m2两个方法。子类覆盖了m2方法。那么如果调用m1,则m1中调用的m2会是子类中定义的m2
这篇文章来自极客时间推出的《零基础学Java》中的FAQ。除了在每节视频课下方回答大家的问题之外,针对大家提出的优质问题或者普遍问题,如果需要更大篇幅的文章解答,则会在FAQ中以文章的方式给出回答。带你零基础入门,夯实Java,课程地址:https://time.geekbang.org/course/intro/181
版权声明: 本文为 InfoQ 作者【臧萌】的原创文章。
原文链接:【http://xie.infoq.cn/article/691714e3fa6937e9a0c3f113a】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论