【问题标题】:When should I initialize class fields inside the constructor and when outside constructor?什么时候应该在构造函数内部初始化类字段,什么时候在构造函数外部初始化?
【发布时间】:2016-03-01 16:55:01
【问题描述】:

假设我有一个带有私有字段“cpuCount”和默认构造函数的类“ComputerInsane”,如下所示:

public class ComputerInsane {

    private int cpuCount = 23;

    public ComputerInsane() {
     //default constructor


     }  

}

现在我可以像上面一样将构造函数之外的 cpuCount 初始化为 23 的值,这样当我在类之外创建类 computerInsane 的实例时,私有字段 cpuCount 将自动初始化为 23。不过我也可以在刚刚声明变量之后将初始化放入构造函数中,如下所示:

public class ComputerInsane {

    private int cpuCount;

    public ComputerInsane() {
     //default constructor

      cpuCount = 23;

     }  

}

这样,当我在调用默认构造函数时创建类 computerInsane 的实例时,它也会自动调用。我的问题是这两种类型的字段初始化之间的实际区别是什么,我应该做第一个还是第二个变体?

更重要的是,假设字段是需要用“new”初始化的其他类的对象,或者是数组,因为它们也需要用“new”初始化。同理,那我要不要去:

public class ComputerInsane {


    private int cpuCount = 23;
    private int[] someArray = new int[10];
    Someclass object1 = new Someclass();


    public ComputerInsane() {
     //default constructor


     }  

}

或者我去:

public class ComputerInsane {

    private int cpuCount;
    private int[] someArray;
    Someclass object1;

    public ComputerInsane(){
     //default constructor

     cpuCount = 23;
     someArray = new int[10];
     object1 = new Someclass();


     }  

}

什么更可取,我应该怎么做?

【问题讨论】:

  • 如果它是字面量或常量,则无关紧要。如果它取决于参数,那么它应该在构造函数中。 (您的示例中有一些语法错误,您可能希望遵守 Java 命名约定)

标签: java initialization


【解决方案1】:

你应该做你认为最简单、最干净的事情。我更喜欢第一个选项,因为它是最简单的恕我直言。

否则它会做同样的事情。

所以你是说不要使用构造函数进行初始化?

实际上,字段初始化都发生在运行时的构造函数中。

我经常听说构造函数用于初始化变量,如果不是,构造函数中“应该”发生的其他事情是什么意思?

因此,无论哪种方式,您都在使用构造函数。注意:在一个简单的班轮上你不能做很多事情。

例如

public MyClass(int num) {
    this.num = num; // has to be in the constructor.
    try { // this could be in an initialiser block, but better here
        this.a = someOperation();
    } catch (IOException e) {
        // must be caught
    }
}

【讨论】:

  • 所以你是说不要使用构造函数进行初始化?我经常听说构造函数用于初始化变量,如果不是,构造函数中“应该”发生的其他事情是什么意思?
  • @OfeliavanAnalhard 它用于变量初始化。但我认为他的意思是说它可能像第一个一样,以防变量不依赖于初始化参数。
【解决方案2】:

在这些特定字段的情况下,cpuCount 看起来不会在运行时发生变化,因此它可能是final 关键字的良好候选者。这表明一个值是一个常数。这种方法有一个特殊的命名约定,还有一个与声明在同一行进行的额外初始化约定。

private final int CPU_COUNT = 23;

但是,您拥有的对象和数组看起来会被操纵。所以它们应该在构造函数中初始化。

private final int CPU_COUNT = 23;

public ComputerInsane() {
    this.someArray = new int[10];
    // etc
}

因此,您的常量值是内联初始化的,最终值的规范也是如此。您的其他值是在构造函数中创建的,因为正如您所说,这是创建实例变量的好地方。

补充阅读

【讨论】:

    【解决方案3】:

    这取决于你将来想做什么。也许你想创建一个新的构造函数来增加你的计数,比如

    public ComputerInsane (int multiCount){ }  
    

    这样就可以了

    private int cpuCount = 23;
    
    public ComputerInsane (int multiCount){ 
       cpuCount *= multiCount;
    }  
    

    或

    private int cpuCount;
    
    public ComputerInsane (int multiCount){ 
       cpuCount = 23 * multiCount;
    } 
    

    使用第一个解决方案您无法创建您可能想要的cpuCount final,第二个解决方案支持将cpuCount 作为final 字段。

    private final int cpuCount;
    
    public ComputerInsane (int multiCount){ 
       cpuCount = 23 * multiCount;
    } 
    

    【讨论】:

      【解决方案4】:

      构造函数外部的初始化在构造函数体之前执行。 了解您是否在构造函数外部和内部都有初始化非常重要,因此构造函数初始化最后执行并覆盖预定义的值。

      如果值始终相同,则最好使用初始化外部构造函数,但如果您有许多构造函数以不同方式初始化字段,所以最好将此逻辑保留在内部构造函数中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-16
        • 1970-01-01
        • 2014-12-12
        • 2019-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多