JAVA/Effective Java

item 4. 인스턴스화를 막으려면 private 생성자를 사용하라.

Garonguri 2022. 4. 12. 01:23
728x90

  • 정적 멤버(정적 메서드, 정적 필드)만 담은 유틸리티 클래스
    • 특징
      • static 선언을 통해 인스턴스를 생성하지 않고 전역 범위에서 사용할 수 있고, 재사용이 가능하게 한다.
      • class field와 method 모두 정적으로 구현되어 있는 경우가 많다.
    • 주로 사용하는 경우
      1. 기본 타입 값이나 배열 관련 메서드를 모아놓을 때 (Java.lang.Math, Java.util.Arrays)
      2. 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모아놓을 때 (Java.util.Collections)
      3. final Class와 관련된 메서드를 모아놓을 때 (- final class를 상속해서 하위 class 메서드에 넣는것이 불가능함)
    • 단점
      • 인스턴스로 만들어 쓰기 위해 설계한 클래스가 아님에도 인스턴스를 만들 수 있다.
      • static field와 static method만 존재함에도 불구하고 인스턴스를 생성할 수 있게 되어, 사용자에게/협업자에게 혼란을 일으킬 수 있다.
      • 인스턴스 생성을 막기 위하여 추상 클래스로 만들더라도 상속해 사용한다면 인스턴스를 만들 수 있다.
    • 해결 방안
      • 생성자의 접근 제한자를 private로 만든다. 즉, private 생성자를 추가한다.
      • 그러나 생성자가 존재함에도 호출할 수 없는 로직이므로, 주석 또는 Exception을 통해 적절한 조치를 취해야 한다
  • 예시

- Java.lang.Math

public final class Math {

    /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}

    public static final double PI = 3.14159265358979323846;

    public static int max(int a, int b) {
        return (a >= b) ? a : b;
    }
    
    //..etc
}

- Java.util.Collections

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

    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }
 // ... etc

}
  • private 으로 접근 제한자가 설정되어 있고, static으로 선언되어 있기 때문에 객체를 생성할 수 없지만, 객체 생성 없이도  사용할 수 있다.
  • 명시적으로 정의하였지만 직관적이지 않으므로, Assertion Error를 던지면 의미를 효과적으로 전달할 수 있다.
728x90