Effective Java #4 객체 생성을 막을 때는 private 생성자를 사용하라
때로는 정적 메서드나 필드만 모은 클래스를 만들고 싶을 때가 있다. 자바의 기본 자료형 값 또는 배열에 적용되는 메서드를 한군데 모아둘 때 유용하다. java.lang.Math나 java.util.Arrays가 좋은 예다.특정 인터페이스를 구현하는 객체를 만드는 팩터리 메서드 등의 정적 메서드를 모아놓을 때도 사용할 수 있다. java.util.Collections는 그 좋은 예다.
이런 유틸리티 클래스들은 객체를 만들 목적의 클래스가 아니다. 객체를 만들면 이상하다. 하지만 생성자를 생략하면 컴파일러는 자동으로 인자 없는 public 기본 생성자를 만들어 버린다. 사용자는 이 생성자를 일반 생성자와 구별할 수 없다. 따라서 원래 의도와는 달리 객체 생성이 가능한 클래스가 공개 API에 포함되느 일도 드물지 않다.
객체를 만들 수 없도록 하려고 클래스를 abstract로 선언해 봤자 소용없다. 하위 클래스를 정의하는 순간 객체 생성이 가능해지기 때문이다. private 생성자를 클래스에 넣어 객체 생성을 방지하자.
1 2 3 4 5 6 7 8 | class UtilityClass { private UtilityClass() { throw new AssertionError(); }; //나머지는 생략 } |
명시적으로 정의된 생성자가 private이므로 클래스 외부에서는 사용할 수 없다. AssertionError는 반드시 필요한 것은 아니지만, 클래스 안에서 실수로 생성자를 호출하면 바로 알 수 있게 하기 위한 것이다. 또한 위와 같이 하면 하위 클래스도 만들 수 없다. 모든 생성자는 상위 클래스의 생성자를 명시적으로든 아니면 묵시적으로든 호출할 수 있어야 하는데, 호출 가능한 생성자가 상위 클래스에 없기 때문이다.