1. 소개

생성자는 객체 지향 디자인 의 문지기입니다 .

이 예제에서는 생성되는 객체 의 내부 상태 를 초기화하는 단일 위치 역할을하는 방법을 알아 봅니다 .

위조하여 은행 계좌를 나타내는 간단한 개체를 만들어 보겠습니다.

2. 은행 계좌 설정

은행 계좌를 나타내는 클래스를 만들어야한다고 상상해보십시오. 이름, 생성 일 및 잔액이 포함됩니다.

또한 toString 메서드를 재정 의하여 세부 정보를 콘솔에 인쇄 해 보겠습니다 .

class BankAccount {
    String name;
    LocalDateTime opened;
    double balance;
    
    @Override
    public String toString() {
        return String.format("%s, %s, %f", 
          this.name, this.opened.toString(), this.balance);
    }
}

이제이 클래스에는 은행 계좌에 대한 정보를 저장하는 데 필요한 모든 필수 필드가 포함되어 있지만 아직 생성자는 포함되어 있지 않습니다.

즉, 새 개체를 만들면 필드 값이 초기화되지 않습니다.

BankAccount account = new BankAccount();
account.toString();

toString  메서드를 실행하면 개체 이름열린 개체 가 여전히 null 이므로 예외가 발생합니다 .

java.lang.NullPointerException
    at com.baeldung.constructors.BankAccount.toString(BankAccount.java:12)
    at com.baeldung.constructors.ConstructorUnitTest
      .givenNoExplicitContructor_whenUsed_thenFails(ConstructorUnitTest.java:23)

3. 인수없는 생성자

생성자로 수정 해 보겠습니다.

class BankAccount {
    public BankAccount() {
        this.name = "";
        this.opened = LocalDateTime.now();
        this.balance = 0.0d;
    }
}

방금 작성한 생성자에 대해 몇 가지 주목하십시오. 첫째, 메서드이지만 반환 유형이 없습니다. 생성자가 생성 한 객체의 유형을 암시 적으로 반환하기 때문입니다. 호출  새 BankAccount가 ()를 이제 위의 생성자를 호출합니다.

둘째, 인수가 필요하지 않습니다. 이러한 특정 종류의 생성자를 o 인수 생성자 라고합니다 .

그런데 왜 처음으로 필요하지 않았습니까? 우리가 때 때문입니다 명시 적으로 생성자를 작성하지 않는 컴파일러는 기본, 인수가없는 생성자를 추가합니다 .

이것이 우리가 명시 적으로 생성자를 작성하지 않았음에도 불구하고 처음에 객체를 생성 할 수 있었던 이유입니다. 기본, 인수 없음 생성자는 단순히 모든 멤버를 기본값으로 설정합니다 .

객체의 경우 이는 null이므로 이전에 본 예외가 발생했습니다.

4. 매개 변수화 된 생성자

이제 생성자의 진정한 이점은 객체에 상태를 주입 할 때 캡슐화를 유지 하는 데 도움이된다는 것 입니다.

따라서이 은행 계좌로 정말 유용한 작업을 수행하려면 실제로 객체에 초기 값을 주입 할 수 있어야합니다.

이를 위해 매개 변수화 된 생성자 , 즉 일부 인수를받는 생성자를 작성해 보겠습니다 .

class BankAccount {
    public BankAccount() { ... }
    public BankAccount(String name, LocalDateTime opened, double balance) {
        this.name = name;
        this.opened = opened;
        this.balance = balance;
    }
}

이제 BankAccount 클래스로 유용한 작업을 수행 할 수 있습니다 .

    LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
    BankAccount account = new BankAccount("Tom", opened, 1000.0f); 
    account.toString();

이제 클래스에 2 개의 생성자가 있습니다. 인수가없는 명시 적 생성자 및 매개 변수화 된 생성자.

생성자를 원하는만큼 만들 수 있지만 너무 많이 만들지는 않을 것입니다. 이것은 약간 혼란 스러울 것입니다.

코드에서 생성자가 너무 많으면 몇 가지 생성 디자인 패턴 이 도움이 될 수 있습니다.

5. 복사 생성자

생성자는 초기화만으로 제한 될 필요가 없습니다. 또한 다른 방법으로 개체를 만드는 데 사용할 수도 있습니다. 기존 계정에서 새 계정을 만들 수 있어야한다고 가정 해보십시오.

새 계정은 이전 계정과 동일한 이름이어야하며 오늘의 생성 날짜 여야하며 자금이 없어야합니다. 복사 생성자 를 사용하여이를 수행 할 수 있습니다 .

public BankAccount(BankAccount other) {
    this.name = other.name;
    this.opened = LocalDateTime.now();
    this.balance = 0.0f;
}

이제 다음과 같은 동작이 있습니다.

LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
BankAccount account = new BankAccount("Tim", opened, 1000.0f);
BankAccount newAccount = new BankAccount(account);

assertThat(account.getName()).isEqualTo(newAccount.getName());
assertThat(account.getOpened()).isNotEqualTo(newAccount.getOpened());
assertThat(newAccount.getBalance()).isEqualTo(0.0f);

6. 체인 생성자

물론 생성자 매개 변수 중 일부를 유추하거나 일부 기본값을 제공 할 수 있습니다 .

예를 들어 이름만으로 새 은행 계좌를 만들 수 있습니다.

따라서 이름 매개 변수가 있는 생성자를 만들고 다른 매개 변수에 기본값을 지정해 보겠습니다 .

public BankAccount(String name, LocalDateTime opened, double balance) {
    this.name = name;
    this.opened = opened;
    this.balance = balance;
}
public BankAccount(String name) {
    this(name, LocalDateTime.now(), 0.0f);
}

this 키워드로 다른 생성자를 호출합니다.

슈퍼 클래스 생성자를 연결하려면 this 대신 super 를 사용해야 한다는 것을 기억해야 합니다 .

또한 this 또는 super 표현은 항상 첫 번째 문장이어야합니다.

7. 값 유형

Java에서 생성자의 흥미로운 용도는 Value Object 생성에 있습니다. 값 개체는 초기화 후 내부 상태를 변경하지 않는 개체입니다.

즉, 객체는 불변 입니다. Java의 불변성은 약간 미묘한 차이 이며 객체를 만들 때주의해야합니다.

계속해서 불변 클래스를 만들어 봅시다 :

class Transaction {
    final BankAccount bankAccount;
    final LocalDateTime date;
    final double amount;

    public Transaction(BankAccount account, LocalDateTime date, double amount) {
        this.bankAccount = account;
        this.date = date;
        this.amount = amount;
    }
}

이제 클래스의 멤버를 정의 할 때 final 키워드를 사용합니다 . 이는 각 멤버가 클래스의 생성자 내에서만 초기화 될 수 있음을 의미합니다. 나중에 다른 메서드 내에서 다시 할당 할 수 없습니다. 이 값을 읽을 수는 있지만 변경할 수는 없습니다.

Transaction 클래스에 대해 여러 생성자를 만드는 경우 각 생성자는 모든 최종 변수를 초기화해야합니다. 그렇게하지 않으면 컴파일 오류가 발생합니다.

8. 결론

생성자가 객체를 빌드하는 다양한 방법을 살펴 보았습니다. 신중하게 사용하면 구문은 Java에서 객체 지향 디자인의 기본 구성 요소를 형성합니다.

항상 그렇듯이 코드 샘플은 GitHub 에서 찾을 수 있습니다 .