无法在构造函数中访问实例变量以调用另一个构造函数

时间:2015-11-15 17:00:39

标签: java constructor

我已经在StackOverFlow中完成了以下两个问题。因此,请不要将我的问题视为重复的问题。

Why can't I refer to an instance method while explicitly invoking a constructor?

Why can't we pass a instance variable to the super class constructor?

我的问题是在调用构造函数之前创建并实例化所有实例变量。这就是为什么我们可以访问构造函数中的所有实例变量,我们也可以在构造函数中调用实例方法而不会失败。但是当我尝试执行以下代码时,我收到编译时错误,即Cannot refer to an instance field limit while explicitly invoking a constructor。此错误是在默认构造函数中调用this(limit)时。

public class Test {

private int limit=10; 

public Test() {
    this(limit);
}   

public Test(int limit) {

}   

}

为什么我收到此错误?在调用Test()构造函数之前,将初始化limit变量。

在上面提到的两个问题中,没有答案为什么我们不能使用实例变量来调用其他构造函数。他们只是说一些无用的答案,即You can not use or call an instance variable or method while calling other constructor but you can use them otherwise但为什么?

为什么我们不能传递一个已经完全初始化并完全准备好用于其他构造函数的实例变量?

如果您有任何有效答案,则只回复。如果您还想提出愚蠢的答案,请转到另一个问题。

5 个答案:

答案 0 :(得分:5)

  在调用Test()构造函数之前,

limit变量将被初始化。

根据Creation of New Class Instances上的Java语言规范部分,这不是真的:

  
      
  1. 将构造函数的参数分配给此构造函数调用的新创建的参数变量。

  2.   
  3. 如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7.1节)开头(使用此),则使用这些相同的五个值来计算参数并以递归方式处理该构造函数调用步骤即可。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续步骤5.

  4.         

    ...

         
        
    1. 执行此类的实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值分配给相应的实例变量,按从左到右的顺序在文本中以该类的源代码。如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常。否则,请继续执行步骤5.
    2.   

因此,在使用limit调用的其他构造函数执行后,初始化字段this(limit)

来自JLS的this section的补充,它解释了编译器错误:

  

构造函数体中的显式构造函数调用语句可能不引用此类或任何超类中声明的任何实例变量或实例方法或内部类,或者在任何表达式中使用this或super;否则,发生编译时错误。

答案 1 :(得分:3)

  

在调用构造函数之前创建并实例化所有实例变量。

不,他们不是。

如果在构造函数外部分配了任何实例字段(如行private int limit=10;中所示),则这些分配发生在thissuper(构造函数的第一行)之后但在其余的构造函数体。

因此,您无法引用构造函数体的this(...)super(...)行中的实例字段。

要了解发生了什么,这是一个例子。 (你不应该在实际代码中以这种方式使用{{。)。

public class Test {

    private Object limit = new Object() {{
        System.out.print("A");
    }};

    public Test() {
        this(new Object() {{
            System.out.print("B");
        }});
        System.out.print("C");
    }

    public Test(Object o) {
        System.out.print("D");
    }

    public static void main(String[] args) {
        new Test();
    }
}

这会打印BADC,证明在分配 limit之前调用了第二个构造函数。

答案 2 :(得分:2)

简单的答案是因为语言规范是这样说的。 JLS 8.8.7.1说:

  

构造函数体中的显式构造函数调用语句可能不引用此类或任何超类中声明的任何实例变量或实例方法或内部类,或者在任何表达式中使用this或super;否则,发生编译时错误。

答案 3 :(得分:1)

在构造函数中调用this()告诉编译器:改为使用其他构造函数(而不是之后,而是!)。因此,实例变量尚未定义在(){和this之间(因为构造对象的作业已被传递给不同的构造函数。这意味着初始化实例变量的作业也已被委派。所以对于你的问题错误:实例变量尚未初始化,因此没有分配任何值。只是做thiis(10);但是没关系。

至少这是我多年前在Java语言基础知识上记忆的方法: - )

答案 4 :(得分:0)

您收到错误是因为在调用超类型构造函数reference)之前,您无法super实例变量。因为你正在调用this(),所以编译器不会调用super()构造函数,假设它将在另一个重载的构造函数中调用。