【问题标题】:Java - passing instance variables to this() methodJava - 将实例变量传递给 this() 方法
【发布时间】:2019-11-16 20:54:45
【问题描述】:

我在学习使用this() 调用重载的构造函数时遇到了这个限制:

你不能在调用中使用构造函数类的任何实例变量 到这个()

例如:

class Test{
    int x;

    public Test() {
        this(x); //Does not compile
    }

    public Test(int y) {}

    void method1() {
        method2(x); //OK
    }

    void method2(int y) {}
}

我知道不需要将实例字段传递给构造函数,因为默认情况下它是可见的。但是,为什么同样的限制不适用于实例方法?

【问题讨论】:

标签: java


【解决方案1】:

Java 中还有一个要求:构造函数调用(使用this() 必须首先在任何构造函数中执行。构造函数将初始化对象。

在这些初始调用之后,实例字段被初始化。因此,由于字段值现在定义良好,您可以将它们用于任何事情,包括调用其他方法。

但是,在初始构造函数调用之前,字段处于未定义状态,不能用作其他构造函数调用的参数。


对于这些你需要查看 JLS 的东西:

  1. 如果此构造函数以同一类中另一个构造函数的显式构造函数调用(第 8.8.7.1 节)开始(使用 this),则评估参数并使用这五个相同的步骤递归地处理该构造函数调用。如果该构造函数调用突然完成,则此过程出于相同原因而突然完成;否则,继续第 5 步。

  2. 执行该类的实例初始化程序和实例变量初始化程序,将实例变量初始化程序的值分配给相应的实例变量,按照它们在源代码中以文本形式出现的从左到右的顺序。如果执行这些初始化程序中的任何一个导致异常,则不会处理更多初始化程序,并且此过程会突然完成相同的异常。否则,继续第 5 步。

所以实例变量只在构造函数调用之后被初始化。这是有道理的,因为首先为其分配默认值(零或空)然后从构造函数中为其分配另一个值会很奇怪。

【讨论】:

    【解决方案2】:

    构造函数构造实例。所以我们不应该期望实例变量x在构造函数启动时被初始化。
    另一方面,实例方法已经可以访问实例变量。没有理由禁止将它们作为参数传递给另一个实例方法。

    但是,当我们开始进一步考虑时,对构造函数的限制就不再那么有意义了。我们也可以在那里访问实例变量,那么为什么我们不能将参数传递给另一个构造函数呢?

    所以一个更好的问题是:Why can't we pass an instance variable to call an overload of our constructor from within our constructor?
    这个问题得到了很好的回答。它甚至可以被认为是重复的(但由于这个借口是理解原因所必需的,所以我写了一个答案而不是简单地标记)。

    在构造函数之外的类主体中声明和初始化的实例字段,例如您的int x;,在调用重载构造函数之后分配

    您可以将其与调用构造函数重载的其他限制进行比较:我们只能在构造函数的第一行这样做。就在一开始。然后,变量尚未初始化。但是它们是在第一个非构造函数调用指令之前初始化的。


    可以在herethere 中找到有关此其他限制的相关信息:

    因为 JLS 是这么说的。是否可以以兼容的方式更改 JLS 以允许它? 是的。

     

    从历史上看,this() 或 super() 必须在构造函数中排在第一位。这 限制从未流行,并被认为是任意的。有 一些微妙的原因,包括验证 invokespecial,这促成了这种限制。这些年来, 我们已经在虚拟机级别解决了这些问题,直到它变成 考虑取消这个限制是切实可行的,不仅仅是为了记录, 但对于所有构造函数。

    【讨论】:

      【解决方案3】:

      您应该教育班级顺序初始化 f.e:https://www.baeldung.com/java-initialization

      调用类构造函数时,int x 字段未初始化。您可以在构造函数中设置(初始化)`int x',但不能调用它。

      我不知道为什么你必须遵循这种方式,但你可以使用static 字段: 类测试{ 静态整数 x;

          public Test() {
              this(x); //Does not compile
          }
      
          public Test(int y) {}
      
          void method1() {
              method2(x); //OK
          }
      
          void method2(int y) {}
      }
      

      您也可以在调用它的行中初始化一个静态字段,

      static int x =4/2;
      

      或在静态块中:

      static int x;
      static {
          x = 4/2;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-02-09
        • 2012-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-15
        • 2016-04-20
        相关资源
        最近更新 更多