为什么每个实例只能调用一次构造函数?

Gur*_*lki 1 java

为什么Java中的构造函数调用只允许每个实例一次?如果在一次调用中设置多个实例变量而不是调用多个setter会很有用.

cle*_*tus 12

如果要一次设置多个变量,只需定义一个函数:

public class Person {
  public Person(String firstName, String lastName, Date dateOfBirth) {
    set(firstName, lastName, dateOfBirth);
  }

  public void set(String firstName, String lastName, String dateOfBirth) {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

根据定义,对象只构造一次,因此构造函数只被调用一次.

值得注意的一点是:支持不变性更为常见,因此:

public class Person {
  private final String firstName;
  private final String lastName;
  private final Date dateOfBirth;

  public Person(String firstName, String lastName, Date dateOfBirth) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.dateOfBirth = dateOfBirth == null ? null new Date(dateOfBirth.getTime());
  }

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public Date getDateOfBirth() { return dateOfBirth == null ? null : new Date(dateOfBirth.getTime()); }

  public Person withFirstName(String firstName) {
    return new Person(firstName, lastName, dateOfBirth);
  }

  public Person withLastName(String lastName) {
    return new Person(firstName, lastName, dateOfBirth);
  }

  public Person withDateOfBirth(Date dateOfBirth) {
    return new Person(firstName, lastName, dateOfBirth);
  }
}
Run Code Online (Sandbox Code Playgroud)

因为当你这样做时,许多并发问题就会消失.不仅仅是并发问题.String,BigDecimal,BigInteger和一些其它标准类是不可变的(不可变的装置实例化一次其状态永远不能改变).Date不是.你在上面的代码中看到我必须不断地防御性地复制出生日期?那是因为Date不是一成不变的.如果你没有调用者可以这样做:

public class Person {
  private final Date dateOfBirth;

  ...

  public Date getDateOfBirth() { return dateOfBirth; }
}

Person person = new Person(...);
Date date1 = person.getDateOfBirth();
date1.setTime(1000000000L);
System.out.println(person.getDateOfBirth());
Run Code Online (Sandbox Code Playgroud)

出生日期将发生变化.这个问题完全是由Date可变引起的.这是支持不变性的另一个原因.

  • 虽然我对这个想法表示赞赏,但我认为如果你将"setter"重命名为withLastName,withDateOfBirth等,那么不变性模式会更加清晰.这使你更明显的是你实际上并没有*在现有实例上设置它. (2认同)

duf*_*ymo 6

您的错误是假设您应该编写默认构造函数并使用setter设置所有值.一个对象在创建时应该100%准备就绪,所以你应该编写一个构造函数来初始化它的整个状态.

这不是Java的"神",这是错误的,是你.