Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 默认构造函数与内联字段初始化_Java_Oop_Constructor - Fatal编程技术网

Java 默认构造函数与内联字段初始化

Java 默认构造函数与内联字段初始化,java,oop,constructor,Java,Oop,Constructor,默认构造函数和直接初始化对象字段有什么区别 有什么理由选择下面的一个例子而不是另一个 例1 例2 选择示例一的原因是,它的功能相同,代码更少(这总是好的) 除此之外,没有区别 但是,如果您确实有显式构造函数,我更愿意将所有初始化代码放入其中(并链接它们),而不是在构造函数和字段初始值设定项之间进行拆分。初始值设定项在构造函数体之前执行。(这意味着,如果同时具有初始化器和构造函数,则构造函数代码将执行第二个并重写初始化值) 当您总是需要相同的初始值(如在您的示例中,给定大小的数组或特定值的整数)时

默认构造函数和直接初始化对象字段有什么区别

有什么理由选择下面的一个例子而不是另一个

例1 例2
选择示例一的原因是,它的功能相同,代码更少(这总是好的)

除此之外,没有区别


但是,如果您确实有显式构造函数,我更愿意将所有初始化代码放入其中(并链接它们),而不是在构造函数和字段初始值设定项之间进行拆分。

初始值设定项在构造函数体之前执行。(这意味着,如果同时具有初始化器和构造函数,则构造函数代码将执行第二个并重写初始化值)

当您总是需要相同的初始值(如在您的示例中,给定大小的数组或特定值的整数)时,初始化器很好,但它可以对您有利或不利:

如果有许多构造函数以不同的方式初始化变量(即使用不同的值),那么初始化器是无用的,因为更改将被覆盖,而且是浪费

另一方面,如果有许多构造函数使用相同的值初始化,则可以通过将初始化保留在一个位置来保存代码行(并使代码更易于维护)


正如Michael所说,这也涉及到品味问题——您可能希望将代码保存在一个地方。尽管如果你有很多构造函数,你的代码在任何情况下都不在一个地方,所以我倾向于使用初始化器。

我能想到的唯一区别是如果你要添加另一个构造函数

public Foo(int inX){
x = inX;
}

在第一个示例中,您将不再拥有默认构造函数,而在第二个示例中,您仍然拥有默认构造函数(如果需要,甚至可以从新构造函数内部调用它)

当有复杂的初始化逻辑要执行时,我更喜欢字段初始值设定项,并求助于默认构造函数(例如,填充一个映射,一个ivar通过一系列启发式步骤依赖另一个ivar来执行,等等)

@迈克尔B说:

。。。我更愿意将所有初始化代码放入这些代码中(并链接它们),而不是在构造函数和字段初始值设定项之间进行拆分


MichaelB(我向71+K代表鞠躬)说得很有道理,但我的倾向是将简单的初始化保留在内联最终初始化器中,并在构造函数中完成复杂的初始化部分。

我们应该支持字段初始化器还是构造函数为字段提供默认值?

我不会考虑在现场实例化和字段懒惰/急于实例化中出现的异常,这些问题涉及到其他的关注点,而不是可读性和可维护性问题。 对于执行相同逻辑并产生相同结果的两个代码,应采用可读性和可维护性最好的方式

TL;DR

  • 选择第一个或第二个选项首先是代码组织、可读性和可维护性的问题

  • 在选择方式上保持一致性(它使整个应用程序代码更清晰)

  • 请毫不犹豫地使用字段初始值设定项来实例化
    集合
    字段,以防止
    NullPointerException

  • 对于可能被构造函数覆盖的字段,不要使用字段初始值设定项

  • 在具有单个构造函数的类中,字段初始值设定项方式通常更具可读性,也不太冗长

  • 在具有多个构造函数的类中,如果构造函数之间没有耦合或耦合很少,则字段初始值设定项方法通常更具可读性且不太冗长

  • 在具有多个构造函数的类中,构造函数之间存在耦合,这两种方法都不是更好的方法,但无论选择何种方法,将其与链接构造函数相结合都是最好的方法(请参见用例1)


操作问题

通过一个非常简单的代码,在字段声明期间的赋值似乎更好,事实也确实如此。

这不太冗长,更直截了当:

public class Foo {
    private int x = 5;
    private String[] y = new String[10];
}
而不是构造函数的方式:

public class Foo{
    private int x;
    private String[] y;

    public Foo(){
        x = 5;
        y = new String[10];
    }
}
在具有如此真实的特殊性的真实课堂上,情况就不同了
事实上,根据遇到的具体情况,一种方式,另一方或其中任何一方都应该受到青睐


更详细的示例来说明

public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat = 5;
  private Color color = Color.black;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat) {
      this.nbSeat = nbSeat;          
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;          
      this.color = color;
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      this.name = "Super car";
      this.origin = "Mars";     
      this.nbSeat = nbSeat;          
      this.color = color; 
  }   

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ...   

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      // assignment at a single place
      this.nbSeat = nbSeat;          
      this.color = color;
      // validation rules at a single place
         ...
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
    initDefaultValues();
  }

  public Car(int nbSeat, Color color) {
     initDefaultValues();
     this.nbSeat = nbSeat;         
     this.color = color;
  }

  public Car(Car replacingCar) {         
     initDefaultValues();
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

  private void initDefaultValues() {
     name = "Super car";
     origin = "Mars";      
  }

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;         
      this.color = color;
  }

  public Car(Car replacingCar) {         
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

}
研究案例1

我将从一个简单的
Car
类开始,我将更新该类来说明这些要点。
Car
声明4个字段以及它们之间存在关系的一些构造函数

1.在字段初始化器中为所有字段指定默认值是不可取的

public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat = 5;
  private Color color = Color.black;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat) {
      this.nbSeat = nbSeat;          
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;          
      this.color = color;
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      this.name = "Super car";
      this.origin = "Mars";     
      this.nbSeat = nbSeat;          
      this.color = color; 
  }   

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ...   

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      // assignment at a single place
      this.nbSeat = nbSeat;          
      this.color = color;
      // validation rules at a single place
         ...
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
    initDefaultValues();
  }

  public Car(int nbSeat, Color color) {
     initDefaultValues();
     this.nbSeat = nbSeat;         
     this.color = color;
  }

  public Car(Car replacingCar) {         
     initDefaultValues();
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

  private void initDefaultValues() {
     name = "Super car";
     origin = "Mars";      
  }

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;         
      this.color = color;
  }

  public Car(Car replacingCar) {         
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

}
字段声明中指定的默认值并不都可靠。 只有
name
origin
字段具有真正的默认值。

nbSeat
color
字段首先在其声明中赋值,然后这些字段可能会在带有参数的构造函数中被覆盖。
它容易出错,此外,使用这种字段赋值方法,该类会降低其可靠性级别。怎么可能 依赖于在字段声明期间指定的任何默认值,而事实证明它对于两个字段都不可靠?

2.使用构造函数对所有字段进行赋值并依赖构造函数链接是很好的

public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat = 5;
  private Color color = Color.black;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat) {
      this.nbSeat = nbSeat;          
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;          
      this.color = color;
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      this.name = "Super car";
      this.origin = "Mars";     
      this.nbSeat = nbSeat;          
      this.color = color; 
  }   

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  ... 

  ... 
  // Other fields

  ...   

  public Car() {  
     this(5, Color.black);
  }

  public Car(int nbSeat) {    
     this(nbSeat, Color.black);       
  }

  public Car(int nbSeat, Color color) {
      // assignment at a single place
      this.nbSeat = nbSeat;          
      this.color = color;
      // validation rules at a single place
         ...
  }   

}
public class Car {

  private String name;
  private String origin;      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
    initDefaultValues();
  }

  public Car(int nbSeat, Color color) {
     initDefaultValues();
     this.nbSeat = nbSeat;         
     this.color = color;
  }

  public Car(Car replacingCar) {         
     initDefaultValues();
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

  private void initDefaultValues() {
     name = "Super car";
     origin = "Mars";      
  }

}
public class Car {

  private String name = "Super car";
  private String origin = "Mars";      
  private int nbSeat;
  private Color color;
  private Car replacingCar;
  ... 

  ... 
  // Other fields

  ... 

  public Car() {         
  }

  public Car(int nbSeat, Color color) {
      this.nbSeat = nbSeat;         
      this.color = color;
  }

  public Car(Car replacingCar) {         
     this.replacingCar = replacingCar;         
     // specific validation rules          
  }

}
这个解决方案非常好,因为它不创建重复,它在一个位置收集所有逻辑:具有最大数量参数的构造函数。
它有一个缺点:需要将调用链接到另一个构造函数
但这是一个缺点吗

3.在字段初始化器中为符合以下条件的字段指定默认值