当前位置: 首页 > news >正文

java 构造器 this_Java 类的构造器中this()和super()的困惑

关于构造器中super的使用,书本上这样写:

“super是指向父类的引用,如果构造方法没有显示地调用父类的构造方法,那么编译器会自动为它加上一个默认的super()方法调用。如果父类由没有默认的无参构造方法,编译器就会报错,super()语句必须是构造方法的第一个子句。”

首先我要纠正一个我刚刚才发现的印象流错误,我之前一直以为,无论有没有自定义构造器,编译器为自动为每个类生成一个“方法体为空的无参构造方法”。但上面那段话,指出了,一个类是有可能没有默认的无参构造方法的。于是我往回翻了书,书上的原文为:

“类可以不定义构造方法,这时编译器会为类隐含声明一个方法体为空的无参构造方法。但当类有明确声明的构造方法时,编译器就不会自动生成无参构造方法了。”

说明一旦你自定义了构造方法,编译器就不会帮你自动生成方法体为空的无参构造方法。我之前的印象流是错的。

我们再来看书本上关于this的描述:

“this表示一个对象的引用,它指向正在执行方法的对象。特别的,在构造方法中通过this关键字调用其他构造方法时,必须放在第一行,否则编译器会报错。且在构造方法中,只能通过this调用一次其他构造方法。”

综合上面的描述,会有一个疑问,能否在同一个构造器中同时显示地使用this和super?

(这个问题在知乎上有讨论,详情请转义阵地。在这里我直接搬运过来了)

假定这里讨论的构造器都没有显式的super()调用,则:

有显式this()调用的构造器就会抑制掉该构造器里隐式的super()调用;

没有显式this()调用的构造器则会得到隐式的super()调用。

this()调用会借助别的重载版本的构造器来做部分初始化,而一连串this()最后来到的构造器必然是没有显式this()调用的,这里就会有显式或隐式的super()调用。举个例子:

public classBase {private intx;publicBase() {//super();//这里开头没有this()调用,编译器会合成隐式的super()调用

this.x = 42;

}

}public class Derived extendsBase {private charc;privateObject o;publicDerived() {this('a'); //这里开头有this()调用,编译器不会合成隐式的super()调用

}public Derived(charc) {this(c, null); //同上,不会合成super()调用

}public Derived(charc, Object o) {//super();//这里开头没有this()调用,编译器会合成隐式的super()调用

this.c =c;this.o = 0;

}

}

作者:RednaxelaFX

链接:https://www.zhihu.com/question/41810504/answer/117132716

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在这个例子里,如果有 new Derived(),则一连串的构造器调用会是:

Derived() //最初的new

Derived(char) //经过this()

Derived(char, Object) //经过this()

Base() //经过super()

Object() //来到Object()

这就是我想说的,一连串this()的最后一个必然不再会在开头有this()调用,而这个开头没有this()调用的构造器就会得到编译器给隐式合成的super()调用。

这里没有直接回答“能不能在同一构造器同时显示调用super()和this()”的问题,但考虑下,如果能的话,最终会有两次super()调用,也就是说我们没有理由,在同一个构造器中同时调用super()和this()。

那么强行在同一个构造器中同时调用super()和this()会发生什么呢?

结果是编译器禁止这样做,无论把哪个放在构造器的第一行,都会出现以下其中一个错误:

Error:(6, 13) java: call to thismust be first statement in constructor

Error:(6, 14) java: call to super must be first statement in constructor

那么super()的调用究竟完成了什么工作?难道它创建了一个父类对象吗?

首先,super是指向“父类”的引用,不是像“this”一样指向一个对象。

由于一个子类的实例会包含其所有基类所声明的字段(所有噢,包括私有,这些字段也需要初始化),外加自己声明的字段。而super()是父类封装对自己声明的字段进行初始化的手段。

所以,并没有创建一个父类对象,因为仅仅有那些父类声明的字段构不成一个完整的实例。

Java对象是这样组织的(概念上):

0bcd508fd2a632feb2959333fc0a9c08.png

一个Derived实例就是一个Derived实例。它的this()会负责初始化自己所声明的字段的部分,而它通过(递归-)调用super()来初始化基类祖先们所声明的字段的部分。

每个Java实例上会记录足够类型信息来表明自己具体是哪个类的实例,这里就是Derived类的实例。

然后每个类的元数据会包括结构信息,例如说自己的superClass是谁。这里Derived类会知道自己的superClass是Base,而Base知道自己的superClass是Object。

当我们需要执行instanceof、checkcast、arraystore之类的涉及类型检查的操作时,类的元数据里的结构信息就派上用场了。

相关文章:

  • java为什么输入else错误_java – 我遇到了一个错误问题,我正在使用“else if”语句....
  • java antlr sql_ANTLR SQL解析器代码
  • java cms gc_G1,CMS及PARALLEL GC的比较
  • java以class开头_JAVA基础:从.class文件中寻找类名
  • Java 习题6 参考答案及解析_java期末复习题答案及解析
  • 猜字小游戏java方法体_java实现猜字小游戏
  • java游戏开发包_LWJGL
  • java的人patch方法_java – 如何在CXF中使用PATCH方法
  • java func_Java通过匿名类来实现回调函数实例总结
  • Java关系表达式x y_Java正则逻辑运算符[X|Y]匹配
  • java将五元换成1元5角_C,一个代码来获得一笔钱转换成四分之一,硬币,镍币,便士[关闭]...
  • java 对方 GBK 乱码_【转】Java编码与乱码---GBK与UTF-8之间的转换
  • mySQL表变量和临时表的区别_SQL Server表变量和临时表的区别
  • 将java类的包注册到map中_java hashmap对象当实参是出现”java:11: 错误: 无法将类 Role中的构造器 Role应用到给定类型;”?...
  • JAVA不是主方法怎么输出_java主方法如何调用非静态方法
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • __proto__ 和 prototype的关系
  • 2017年终总结、随想
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • canvas 五子棋游戏
  • Golang-长连接-状态推送
  • Java多线程(4):使用线程池执行定时任务
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • Zepto.js源码学习之二
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 看域名解析域名安全对SEO的影响
  • 码农张的Bug人生 - 初来乍到
  • 算法系列——算法入门之递归分而治之思想的实现
  • 微服务入门【系列视频课程】
  • 为什么要用IPython/Jupyter?
  • 优化 Vue 项目编译文件大小
  • 云大使推广中的常见热门问题
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​configparser --- 配置文件解析器​
  • ​力扣解法汇总946-验证栈序列
  • #pragma 指令
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (二)c52学习之旅-简单了解单片机
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (规划)24届春招和25届暑假实习路线准备规划
  • (未解决)macOS matplotlib 中文是方框
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .Net Redis的秒杀Dome和异步执行
  • .net 调用php,php 调用.net com组件 --
  • .NET面试题(二)
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .Net下的签名与混淆
  • @media screen 针对不同移动设备
  • [ Linux Audio 篇 ] 音频开发入门基础知识