주니어 개발자 성장기

아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라 본문

Java/이펙티브 자바

아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라

Junpyo Lee 2023. 7. 13. 20:37
  • 간혹 인스턴스화를 막는 것이 바람직한 유틸리티성 클래스들이 있다.
    • public static 메서드를 가진 클래스들
    • 로직을 도와주는 성격의 클래스
    • ex) org.springframework.util.StringUtils, java.lang.Math, java.util.Arrays, java.util.Collections와 같은 유틸리티 클래스가 있다.
  • 유틸리티 클래스는 public static 메서드만 제공하기 때문에 인스턴스화가 필요하지 않으며, 인스턴스를 통한 메서드 호출은 오히려 인스턴스 메서드와 정적 메서드간의 혼동을 불러 일으킨다. 따라서, 인스턴스화를 방지하는 것이 바람직하다.
  • 인스턴스화를 방지하기 위해서 abstract로 클래스를 만들 수 있다.
  • 하지만 이 방법은 인스턴스화를 방지할 수 없다.
    • 자바 컴파일러는 생성자를 명시하지 않으면 기본 public 생성자를 만든다.
    • 만약, 하위클래스를 만들어 상속하게 되면 해당 클래스의 인스턴스를 만들 수 있게된다.
  • 그래서 대안은 private 생성자를 명시적으로 선언하는 것이다.
	private UtilityClass() {}

 

  • 하지만, 내부에서 private 생성자를 호출할 수도 있기 때문에 내부에서의 인스턴스 생성까지 막기 위해서는 기본 생성자에서 에러(AssertionError) throw하도록 하면된다.
    private UtilityClass() {
        throw new AssertionError();
    }
  • 하지만, 생성자가 분명 존재하는데 호출을 막는 코드는 직관적이지 않다. 따라서, 문서화를 해서 왜 private 생성자를 만들었는지 명시하는 것이 바람직하다.
  • 게다가 이 방식은 상속을 불가능하게 하는 효과도 있다. (자식 클래스에서 부모 클래스의 생성자를 호출할 수 없기 때문에)
  • 사실, Spring 의 많은 유틸리티 클래스들은 이 방법을 쓰지 않고 있다.

결론

  • 유틸리티 클래스는 private 생성자를 명시함으로써 인스턴스화를 방지할 수 있다.
  • 인스턴스화를 완전히 차단하기 위해서 Errorthrow하도록 할 수 있다.
  • private 생성자를 사용한다면 문서화를 통해 목적을 명시하자.