写点什么

《零基础学 Java》 FAQ 之 12- 理解引用

用户头像
臧萌
关注
发布于: 2020 年 05 月 23 日
《零基础学 Java》 FAQ 之 12-理解引用

引用是什么



@梁大瓜 在 “76 | 多态里更多的语法点(上)” 里说到



老师我这样理解不知道对不对:声明引用实际上就是在堆中建立里一块引用类的内存地址指向,

这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域中放入子类覆盖了与父类相同方法的值。

所以在调用的时候,返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。



回答



声明引用实际上就是在“内存”(可以是堆,比如是一个成员变量,也可以是线程栈,比如说说一个局部变量或者参数)中建立里一块(32bit或者64bit大小)引用“对象”的内存地址指向,这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域(32bit或者64bit大小,和对象类型以及大小没关系,只是一个地址)中放入“子类或者本类的对象的地址”。所以在调用(调用什么?方法吗?)的时候,(后面感觉有点模糊,你可以再说的清楚一点)返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。



其实覆盖不复杂,核心就是:寻找调用哪个方法。这里有两个角色:



  1. 引用的类型,调用的方法签名必须是这个类型中定义了的;

  2. 引用实际指向的对象,它决定的是通过这个签名调用的实际是哪个类的方法。



结合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. 父类引用指向子类对象,可以调用子类覆盖了父类的方法(覆盖,多态)

  3. 父类引用指向子类对象,在1)和2)这两种情况下。如果这个方法的代码中又调用了别的方法,那么还是会遵循这个规则。举个例子,如果父类中有m1,m2两个方法。子类覆盖了m2方法。那么如果调用m1,则m1中调用的m2会是子类中定义的m2






这篇文章来自极客时间推出的《零基础学Java》中的FAQ。除了在每节视频课下方回答大家的问题之外,针对大家提出的优质问题或者普遍问题,如果需要更大篇幅的文章解答,则会在FAQ中以文章的方式给出回答。带你零基础入门,夯实Java,课程地址:https://time.geekbang.org/course/intro/181



发布于: 2020 年 05 月 23 日阅读数: 353
用户头像

臧萌

关注

一线程序员,偶尔写写字 2017.10.20 加入

《零基础学 Java》,《职场求生攻略》 视频课作者 《Java入门1·2·3》作者

评论

发布
暂无评论
《零基础学 Java》 FAQ 之 12-理解引用