java 中关键字 super 表示的真正对象

本贴最后更新于 2683 天前,其中的信息可能已经渤澥桑田

Java 中关键字 super 表示的真正对象
java 中的 super,大家都知道是表示一个父类的引用。上次群里见到一个网友询问 super.getClass().getName()的输出问题,大部分都知道输出的是当前这个类的类名。而不是父类的名称。关于这个问题的解释很多,基本都是说 getClass()是一个 final 方法,说这个方法都是调用超父类 Object 的方法。这个解释很好,也容易理解,不过,我们从 super 这个关键词的本质入手,就能更清楚,为什么 super.getClass().getName()会输出当前类的名称了。

先定义两个类,一个父类,一个继承的子类。

父类:

[java] view plain copy

  1. public class Parent {
  2.  public String name;  
    
  3.  private int code;  
    
  4.  public Parent parent;  
    
  5.  //定义几个父类成员属性,parent将指向this父类对象  
    
  6.  public Parent()  
    
  7.  {  
    
  8.      //parent指向this,就是当前实例的父类对象,并输出hashcode和给code属性赋值  
    
  9.      parent=this;  
    
  10.      code=1001;  
    
  11.      System.out.println("Parent's code is:"+code);  
    
  12.      System.out.println("Parent hashcode is:"+this.hashCode());  
    
  13.  }  
    
  14.  //定义一个重载的构造方法,用于测试使用了哪个父类构造方法  
    
  15.  public Parent(String name){  
    
  16.      parent=this;  
    
  17.      this.name=name;  
    
  18.      System.out.println("Parent's name is"+name);  
    
  19.      code=1002;  
    
  20.      System.out.println("Parent's code is"+code);  
    
  21.      System.out.println("Parent hashcode is:"+this.hashCode());  
    
  22.  }  
    
  23.  public int getCode()  
    
  24.  {  
    
  25.      //打印父类code属性值,  
    
  26.      System.out.println("Parent :print code :"+code);  
    
  27.      return code;  
    
  28.  }  
    
  29. }

子类:

[java] view plain copy

  1. public class Child extends Parent{
  2.  public String childName;  
    
  3.  private int childCode;  
    
  4.  //定义两个类的不同修饰符的属性  
    
  5.  public Child(String childName)  
    
  6.  {  
    
  7.      //给属性赋值  
    
  8.      this.childName=childName;  
    
  9.      //输出属性值,和类的hashcode值  
    
  10.      System.out.println("child's childName is:"+childName);  
    
  11.      System.out.println("child hashcode is:"+this.hashCode());  
    
  12.  }  
    
  13.  //测试方法  
    
  14.  public void test()  
    
  15.  {  
    
  16.      //通过super获取父类中的parent,这个成员就表示了父类对象。  
    
  17.      Child testChild=(Child)super.parent;  
    
  18.      //强转parent为子类类型。并输出子类中定义的属性,和获取父类getCode()方法  
    
  19.      System.out.println("testChild name is:"+testChild.childName);  
    
  20.      testChild.getCode();  
    
  21.  }  
    
  22.  public static void main(String[] args) {  
    
  23.      //实例化  
    
  24.      Child c=new Child("window");  
    
  25.      c.test();  
    
  26.  }  
    
  27. }

运行输出结果:

Parent's code is:1001

//首先输出这句,可以表示,父类默认的构造方法执行了。
Parent hashcode is:11985823

//这里输出的父类 this 对象的 hashcode 码

child's childName is:window

//调用子类的构造方法,输出childName和hashcode码值,大家可以看到,父类的this对象和子类实例的对象,hashcode码是相同的。

child hashcode is:11985823

//这里执行test()方法的结果。

//使用Child testChild=(Child)super.parent 强制转换父类中指向父类this对象的parent对象为子类Child对象,并输出子类childName属性值。

testChild name is:window

//输出结果上可以看出,这个parent其实就是子类的实例对象。应该说内存中的对象是同一个,只是不同的表示方式。

//执行testChild.getCode(); 调用父类的getCode()方法,输出的和父类构造方法中的code值是相同的。

Parent :print code :1001

从上面可以看出 super 这个关键字所表示的引用父类对象,其实和当前实例化的子类对象在内存中是同一个对象,虽然不知道 sun 的虚拟机是如何实现这个关键字的,但是这个 super 的等同效果就是(Parent)this,这里的 this 是当前代表当前实例化的子类对象。

通过在父类中添加一个 Parent 类型的成员,来指向父类实例化的那个 this 对象,达到引用父类对象的目的,使用 super.parent 来获得父类 parent 对象的引用。

运行的结果表明,这个 parent 应用的其实就是当前子类实例对象,通过强制转换为子类类型,这个父类 Parent 类型的 parent 也可以读取成员 childName 属性值。就表明了他们在内存中是同一个对象。而且他们的 hashcode 值也是相同的。

java 说明中指出,super 是代表父类对象的引用,而 super()表示应用父类的默认构造方法,看起来这个 super 和 c 中的 define 有点相同作用的效果。在这个例子中,super 代表的父类对象的引用,和父类中 parent 代表的都是父类对象的引用,parent 其实就是当前内存中子类对象的引用,如同(Parent)this 一样,这样就可以解释为什么使用(Child)super.parent 可以得到子类成员 childName。

回到开始的问题,super.getClass().getName(),这样,就很容易解释他为什么是输出当前类的名称了,因为构造一个实例化对象,其中,在父类和子类构造方法中,引用的对象都是同一个,都是当前实例化的子类对象。super 关键字应该充当了一个类型转化的作用。

熟悉 c 的知道,c 中经常使用强制转换指针类型来引用一些结构或变量的部分数据,如通过强制转换为不同结构类型,来引用不同数据大小的结构体。这里的应用效果应该等同,通过(Parent)Child 可以通过转换为父类类型而只引用父类类型的那一部分数据。

在 java 中 new 一个对象,和 c 或 c++ 这些和内存打交道的语言一样,都是会分配内存,在 c 中可能更直观一点,我们在此不讨论到底是分配了多大的内存问题。

在 new 一个子类的时候,上面例子看到,父类的成员同样也有赋值初始化,说明,同样在内存中也有保存父类的信息空间,(Object 类的不讨论)。

  • super
    1 引用 • 1 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    164 引用 • 1451 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 92 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 21 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    370 引用 • 1215 回帖 • 582 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    40 引用 • 40 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6560 引用 • 29454 回帖 • 247 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    173 引用 • 990 回帖
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖 • 1 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    21 引用 • 37 回帖 • 512 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    75 引用 • 258 回帖 • 625 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    275 引用 • 682 回帖
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    492 引用 • 1383 回帖 • 374 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 125 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 25 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    20 引用 • 74 回帖 • 1 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    51 引用 • 37 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 25 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 112 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    148 引用 • 257 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 443 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 619 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 399 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 352 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 28 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    5 引用 • 26 回帖 • 492 关注
  • 自由行
    1 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 6 关注