[Item 4] 인스턴스화를 막으려거든 private 생성자를 사용하라.

손현경 (보름)·2023년 6월 29일

effective-java

목록 보기
4/4

정적 메서드와, 정적 필드만을 담은 클래스를 만들고 싶을 때가 있습니다.

  • java.util.Arrays
  • java.util.Collections
  • final 클래스와 관련한 메서드를 모아 놓을 때
  • 각종 유틸리티 클래스

위 같은 경우는 생성자가 필요 없습니다. (인스턴스로 만들어 쓰려고 설계한 것이 아닙니다.)

Default 생성자

그러나 생성자를 명시하지 않으면, 컴파일러가 자동으로 파라미터를 받지 않는 기본 생성자를 만들어 줍니다. 코드로 실습해 보았습니다.

public class Apple {

  private String name;
}
public static void main(String[] args) {
  Apple apple = new Apple(); // 컴파일러가 자동으로 만든 매개변수를 받지 않는 생성자.
  //Apple apple = new Apple("apple");
}

Apple의 생성자를 작성하지 않았는데도, 기본 생성자를 호출 할 수 있습니다.

이는 클라이언트를 헷갈리게 합니다. 클라이언트는 이 생성자가 자동 생성된 것인지, 명시된 것인지 구분할 수 없습니다.

인스턴스화 막는 방법

추상 클래스로 만들기 - X

그렇다면 추상 클래스로 만들면 인스턴스화가 안되니까 추상 클래스로 만들면 되겠네?

아닙니다. 하위 클래스를 만들어서 인스턴스화 하면 그만입니다.

public abstract class Person {

}
public class Student extends Person {

}
public static void main(String[] args) {]
  Person person = new Student();
}

+) 클라이언트의 입장에서는 추상 클래스니까 상속해서 써야 하는 것이라고 혼동할 수도 있겠습니다.

private 생성자 추가하기 - O

public class Util {

  private Util() {
    
  }
}

이제 바깥 클래스에서 생성자를 호출할 수 없습니다.

private Util() {
  throw new AssertionError();
}

내부에서라도 호출하지 않게끔 private 생성자 안에서 에러를 던질 수 있습니다.

상속 역시 불가합니다. 모든 생성자는 상위 클래스의 생성자를 호출해야 하는데, 이를 private으로 선언했으니 접근 불가하기 때문입니다.


java.util.Arrays의 private 생성자

public class Arrays {
  private static final int MIN_ARRAY_SORT_GRAN = 8192;
  private static final int INSERTIONSORT_THRESHOLD = 7;

  private Arrays() {
  }

java.util.Collections의 private 생성자

public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }

주석으로 호출하면 안되는 생성자임을 표현하고 있습니다.

profile
빛나는 개발자가 되는 그날까지...

0개의 댓글