关于java:为什么带有不同参数的多个`this()`在父构造函数中不起作用?

why multiple `this()` with different argument doesn't work in the parent Constructor?

本问题已经有最佳答案,请猛点这里访问。

为什么this()需要在构造函数链接的第一个语句中?

为什么具有不同参数的多个this()在最终构造函数中不起作用?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package thislatest;

public class ThisLatest {

    public static void main(String[] args) {
            A a1= new A(10,20,30);
            a1.display();
    }

}

class A
{
    int x,b;
    static int c;
    A(){ System.out.println("constructor chaining1");}

    A(int y)
     {   //this();
         System.out.println("constructor chaining2");
         b=y;
     }

    A(int x,int y)
     {
        // this(x);
         System.out.println("constructor chaining3");
         x=x;
         x=y;
     }

       A(int x,int y,int c)
     {   this();
         this(y);
         this(x,y);
         x=x;               //self reference initialised by previous constructor
         b=y;               //no need of this keyword since name is different
         this.c=c;         //current instance variable  or A.c=c will also work
     }

     void display()

     {
        System.out.println(x+b);            //wrong result due to self reference
        System.out.println(c+b);            //correct reference
     }

}

为什么我不能在构造函数A(int x,int y,int c)中使用多个this()

为什么这需要成为第一个声明?

只是为了保持语言的流动吗?

我是初学者,请使用简单的术语:)


不允许在同一个构造函数中调用多个构造函数,但允许将它们链接起来以便一个调用另一个,依此类推。可以这样做,直到类中的构造函数用完为止。考虑下面的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyClass() {
    public MyClass() {
        this(1);
        System.out.printf("Calling MyClass()%n");
    }

    public MyClass(int a) {
        this(a, 2);
        System.out.printf("Calling MyClass(%d)%n", a);
    }

    public MyClass(int a, int b) {
        System.out.printf("Calling MyClass(%d, %d)%n", a, b);
    }
}

以及以下客户代码:

1
2
3
4
5
public class Client() {
    public static void main(String[] args) {
        new MyClass();
    }
}

如果您运行上面的代码,输出将是:

1
2
3
Calling MyClass(1, 2)
Calling MyClass(1)
Calling MyClass()

上面输出的顺序似乎是错误的,因为printf()调用是在构造函数调用之后完成的。通过以下箭头,您可以看到构造函数调用的开始位置和最终结束位置:

1
2
3
4
5
6
7
8
9
Object        MyClass               Client
------        -------               ------
              MyClass() <---------- main(String[])
                 |
                 V
              MyClass(int)
                 |
                 V
Object() <--- MyClass(int, int)

如果你想知道最后一个箭头意味着什么:所有的Java类,包括EDCOX1(1),都会秘密地扩展EDCOX1,2,D类。MyClass中的最后一个构造函数实际上如下所示:

1
2
3
4
    public MyClass(int a, int b) {
        super();
        System.out.printf("Calling MyClass(%d, %d)%n", a, b);
    }

您的类至少需要一个隐式或显式调用super()的构造函数,否则构造函数链将陷入循环中。如果发生这种情况,编译器会给您一个错误。


为什么这个()需要在构造函数链接的第一个语句中?因为它是Java规范所要求的!例如,python允许程序员在任何地方调用超类初始化方法。但是Java不允许这样做。完全停止。

为什么具有不同参数的多个this()在最终构造函数中不起作用?回答同上。问为什么是没用的,想想怎么做,因为你不会改变语言规范。

所以让我们想想怎么做。您可能有充分的理由调用初始化方法,而不是作为构造函数的第一条指令。在这种情况下,只需使用非构造函数初始化方法,并从构造函数调用这些方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A {
    private void init1(int x) {
        // do something with x
    }

    private void init2(int x, int y) {
        // do something with x and y
        ...
        init1(x); // eventually call init1 in the middle of init2
        ...
    }

    A(int x) {
        y = 2 *x + 1;
        init2(x, y);    // call initialization method in the middle of ctor
    }
    A(int x,int y) {
        // eventually some instructions
        init2(x, y);
        // eventually other instructions
    }
}

在Java语言中,构造函数是特殊的。如果你不能接受,你就必须用另一种语言。


每个构造函数初始化类的单个实例。因此,在构造函数中,只能调用另一个构造函数。构造函数调用必须是第一个调用的原因是您将实例的创建委托给另一个构造函数。否则,如果构造函数的第一行不是对另一个构造函数的调用,则实例已经在执行第一行之前实例化(即隐式调用super())。因此,在后面调用构造函数就像在构造函数中第二次调用某个构造函数,显然这是非法的,因为构造函数只实例化一个实例。