gpt4 book ai didi

Java显式构造函数调用和实例初始化器

转载 作者:搜寻专家 更新时间:2023-11-01 02:29:51 26 4
gpt4 key购买 nike

在 Java 教程中 - Initializing Fields , 有关于Instance Initialization Blocks(Instance Initializer)的描述:

The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.

如果释义正确,则为如下代码:

public class ConstructorTest {

public static void main(String[] args) {
Child c = new Child();
}
}

class Parent {
Parent() {
System.out.println("Parent non-argument Constructor");
}
}

class Child extends Parent {

{
System.out.println("Child Instance Initialization Block");
}

Child() {
this(2);
System.out.println("Child no-argument Constructor");

}

Child(int i) {
this(10, i);
System.out.println("Child 1-argument Constructor");
}

Child(int i, int j) {
System.out.println("Child 2-argument Constructor");
}
}

输出应该是:

Parent non-parm Constructor
Child Instance Initialization Block
Child 2-argument Constructor
Child Instance Initialization Block
Child 1-argument Constructor
Child Instance Initialization Block
Child no-argument Constructor

但实际输出是:

Parent non-argument Constructor
Child Instance Initialization Block
Child 2-argument Constructor
Child 1-argument Constructor
Child no-argument Constructor

是我误解了那句话的意思,还是描述的不够准确?

还有一个关于显式构造函数调用的疑问:

基于两个基础:

  • 如果存在,另一个构造函数的调用必须在构造函数的第一行。
  • 在一个构造函数中,使用this()调用另一个构造函数,使用super()调用直接父类对应的构造函数。

是否意味着在子类的构造函数中使用 this() 将隐式删除对父类(super class)的无参数构造函数的默认调用?

感谢回复。

最佳答案

编辑:事实证明 JLS 毕竟是准确的,尽管它很难阅读。 section 12.5 中有详细说明:

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

  2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

  5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

注意突出显示的部分 - 链式构造函数被执行,然后我们跳过第 4 步,这将执行实例初始化程序

现实是实例和字段初始值设定项只执行一次,正如您从输出中可以看出的那样。

非正式地,我认为将过程描述为是准确的:

  • 在同一个类中保持链接构造函数 (this(...)),直到您到达一个不以 this 开头的构造函数主体。
  • 执行适当的 super 构造函数
  • 执行实例变量初始化器和实例初始化器
  • 执行“最内层”构造函数的主体
  • 不断弹出构造函数体堆栈,直到得到“入口”构造函数为止

Is that MEANS use this() within subclass's constructor will implicit remove the default call to the no-argument constructor of the superclass?

是的。在类的构造函数链中的某处,您肯定会得到一个隐式或显式调用super 的构造函数。那是被调用的唯一父类(super class)构造函数。

编辑:请注意,您引用的教程显然是不正确的。

示例类:

public class Test {
    {
        System.out.println("Foo");
    }
    
    public Test() {
    }
    
    public Test(int i)  {
        this();
    }
}

javap -c 的输出:

public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>": ()V
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String Foo
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: return

public Test(int);
Code:
0: aload_0
1: invokespecial #5 // Method "<init>":()V
4: return
}

如您所见,Test(int) 的构造函数没有将实例构造函数的代码编译到其中。

基本上,只有直接调用父类(super class)构造函数的构造函数才会将实例初始化代码复制到其中。当然,所有其他构造函数最终都会通过调用父类(super class)构造函数的构造函数导致实例初始化代码被执行

关于Java显式构造函数调用和实例初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12253712/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com