【问题标题】:Java - Method executed prior to Default Constructor [duplicate]Java - 在默认构造函数之前执行的方法[重复]
【发布时间】:2015-09-21 06:27:44
【问题描述】:

我正在学习 java,偶然发现了以下代码,其中在方法之后执行了默认构造函数。

公共类 ChkCons { int var = getVal(); ChkCons() { System.out.println("我是默认构造函数。"); } 公共 int getVal() { System.out.println("我在方法中。"); 返回 10; } 公共静态无效主要(字符串[]参数){ ChkCons c = 新的 ChkCons(); } }

输出:

我在方法。 我是默认构造函数。

谁能解释一下为什么会这样?

谢谢。

【问题讨论】:

  • 字段在构造函数被调用之前被初始化,因为你的字段初始化调用getVal方法,它在构造函数之前被调用
  • 好吧,那么 getVal() 也会在 STATIC BLOCK 之前执行吗?
  • 构造函数?不,但static 块(来自内存)将在字段之前执行一次

标签: java constructor


【解决方案1】:

实例变量初始化表达式,例如int var = getVal();,在超类构造函数执行之后但在当前类构造函数主体执行之前求值。

因此,getVal()ChkCons 构造函数的主体执行之前被调用。

【讨论】:

  • 好吧,那么 getVal() 也会在 STATIC BLOCK 之前执行吗?
  • @RohitNigam 不,静态初始化块在类初始化时执行。这发生在初始化该类的任何单个实例之前。
  • @RohitNigam 怎么可能?它需要一个实例。静态块中没有实例。想一想。
  • @Holger 也许我的措辞不准确。我的意思是实例变量初始化发生在当前类的构造函数的代码执行之前。什么时候执行超类的构造函数的代码我什么都没说。
  • 您应该将getVal() 保留为静态方法。
【解决方案2】:

在方法之前调用构造函数。方法的执行发生在对象创建的一部分之后,其中实例变量被评估。从下面的代码可以更好地理解。

class SuperClass{
    SuperClass(){
        System.out.println("Super constructor");
    }
}
public class ChkCons extends SuperClass{

    int var = getVal();

    ChkCons() {
        System.out.println("I'm Default Constructor.");
    }

    public int getVal() {
        System.out.println("I'm in Method.");
        return 10;
    }

    public static void main(String[] args) {

        ChkCons c = new ChkCons();

    }

}

以上代码有如下输出

Super constructor
I'm in Method.
I'm Default Constructor.

这里编译器自动添加super();作为ChkCons()构造函数的第一条语句,因此它在getVal()方法之前被调用。

【讨论】:

    【解决方案3】:

    我们可以参考以下关于初始化实例变量的 oracle 文档(重点是我的):

    初始化实例成员

    通常,您会将初始化实例变量的代码放在 构造函数。 使用构造函数有两种选择 初始化实例变量:初始化块和最终方法。

    实例变量的初始化块看起来就像静态的 初始化块,但没有 static 关键字:

    { // 初始化所需的任何代码都放在这里 }

    > Java 编译器将初始化程序块复制到每个构造函数中。 因此,这种方法可以用来在之间共享一个代码块 多个构造函数。

    最终方法不能在子类中被覆盖。这是讨论的 在关于接口和继承的课程中。这是一个例子 使用 final 方法初始化实例变量:

    class Whatever {
    private varType myVar = initializeInstanceVariable();
    
    protected final varType initializeInstanceVariable() {
    
        // initialization code goes here
    } 
    }
    

    https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

    【讨论】:

      【解决方案4】:
      public class InitializerIndex {
      
          public InitializerIndex() {
              // TODO Auto-generated constructor stub
              System.out.println("Default Constructor");
          }
      
          static {
      
              System.out.println("Static Block one");
          }
      
          {
              System.out.println("Init one");
          }
      
          void letsRoll() {
      
          }
      
          public static void main(String[] args) {
              new InitializerIndex().letsRoll();
              new InitializerIndex().letsRoll();
          }
      
          {
              System.out.println("Init Two");
          }
      
          static {
              System.out.println("Static Block two");
          }
      
      }
      

      会有以下输出:

      Static Block one
      Static Block two
      Init one
      Init Two
      Default Constructor
      Init one
      Init Two
      Default Constructor
      

      首先加载所有静态内容,然后加载实例内容。静态内容只加载一次。

      即使创建了两个对象,也只有在创建第一个对象时才调用静态块

      此外,在创建对象时或在构造函数中,如果您想使用这样的方法

       int var = getVal();
      

      你应该使用静态方法。

      【讨论】:

        【解决方案5】:

        每当你创建一个类的实例时,实例变量首先被初始化然后执行构造函数

        参考:Are fields initialized before constructor code is run in Java?

        【讨论】:

          【解决方案6】:

          这是因为你正在使用int var = getVal();将方法初始化为一个字段,所以它会在构造函数调用之前执行。 静态块优先,在加载类时执行。

          【讨论】:

            猜你喜欢
            • 2020-07-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-05
            • 2015-08-20
            • 2014-03-24
            • 2012-06-22
            • 1970-01-01
            相关资源
            最近更新 更多