这说明了从超类构造函数的子类中调用继承方法的危险。主要危险在于,超类构造函数完成 后 ,子类中变量的初始化器就会运行。
这是发生了什么。
- 的对象
y
已创建。 X()
调用超类构造函数,该构造函数调用read()
。- 该
read
方法创建一个新方法Object
并将其传递给readValue
,该方法在中实现Y
。 - 中的
readValue
方法Y
设置obj
为新对象。 - 超类构造函数
X()
完成,并且初始化器 现在 在中运行,并将Y
设置obj
为null
。 - 该
printer
方法打印"Object = null"
。
如果删除
objin 中的声明
Y,则没有初始化程序可运行,并且
obj变量保留其值。
在JLS,12.5节,状态:
将新对象中的实例变量(包括在超类中声明的实例变量)初始化为其默认值(第4.12.5节)。
在返回对新创建对象的引用作为结果之前,使用以下过程处理指示的构造函数以初始化新对象:
- 将构造函数的参数分配给此构造函数调用的新创建的参数变量。
2.
如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7节)开始(使用此方法),则使用相同的五个步骤评估参数并递归处理该构造函数调用。如果该构造函数调用突然完成,则该过程由于相同的原因而突然完成;否则,请继续执行步骤5。3.
此构造函数并不以对同一个类中的另一个构造函数的显式构造函数调用(使用此函数)开头。如果此构造函数用于Object以外的其他类,则此构造函数将以显式或隐式调用超类构造函数(使用super)开始。使用这五个相同的步骤来递归评估超类构造函数调用的参数和过程。如果该构造函数调用突然完成,则出于相同原因,此过程也会突然完成。否则,请继续执行步骤4。
执行该类 的实例初始值设定项 和实例变量初始
值设定项,并按从左到右的顺序将实例变量初始值设定项的值分配给相应的实例变量,这些变量在文本中显示在该类的源代码中。如果执行这些初始化程序中的任何一个导致异常,则不会再处理其他初始化程序,并且该过程会因相同的异常而突然完成。否则,请继续执行步骤5。执行此构造函数的其余部分。如果该执行突然完成,则出于相同原因,此过程也会突然完成。否则,此过程将正常完成。
(强调我的)
和
与C
++不同,Java编程语言没有在创建新的类实例的过程中为方法分派指定更改的规则。如果调用的方法在要初始化的对象的子类中被覆盖,则即使在完全初始化新对象之前,也会使用这些覆盖方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)