[Effective Java 3/E - 객체 생성과 파괴] Item 4. 인스턴스화를 막으려거든 private 생성자를 사용하라
기본 타입의 값 또는 관련 메서드를 모아놓는 용도
인스턴스화를 막기 위해 "생성자를 안쓰면 되지 않나?" 라고 생각할 수 있지만, 개발자가 생성자를 구현하지 않을 경우 컴파일러가 public 기본 생성자를 만들어주기 때문에 private 생성자를 사용하여 인스턴스화를 막아야 합니다.
우선 첫번째로 java.util.Math는 private 생성자를 사용하여 인스턴스화를 막아둔 모습을 확인할 수 있습니다. Math처럼 기본 타입의 값들을 모아놓는 용도로 사용하기 위해 인스턴스화를 막아두는 케이스가 있습니다.
두번째로는 아래의 코드처럼 모든 메서드가 static인 클래스에서도 모든 메서드가 정적 메서드이므로 인스턴스화를 할 이유가 없기 때문에 이러한 클래스를 구현할 때 private 생성자를 사용하여 인스턴스화를 막아주는 것이 좋습니다.
UnsupportedOperationException은 지원되지 않는 요청이라는 뜻을 가진 예외로써 만약 개발자가 실수로 같은 클래스 내에서 private 생성자에 접근하면 예외를 발생시켜 개발자의 실수를 방지할 수 있습니다.
private 생성자 안에 예외를 발생시키는 것은 필수는 아니며, Exception 종류또한 다른 것을 사용해도 괜찮습니다.
public class Calc {
private Calc() {
throw new UnsupportedOperationException("인스턴스화 금지");
}
public static int add(int a, int b) {
return a + b;
}
public static int mul(int a, int b) {
return a * b;
}
}
추상 클래스도 인스턴스화가 안되지 않나?
일반적인 상황에서 추상 클래스는 인스턴스화를 할 수 없습니다. 하지만, 만들때의 의도와는 다르게 개발자가 해당 추상 클래스를 상속받아 구현을 할 수 있기 때문에 단순히 추상 클래스만으로는 인스턴스화를 막을 수 없습니다.
이러한 이유로 인스턴스화를 막고 싶다면 추상 클래스를 사용하는 방법보다는 private 생성자를 가짐으로써 외부에서 접근이 불가능하며 클래스 내부에서만 접근 가능하게 하고 혹여나 개발자의 실수로 클래스 내부에서 생성자를 호출할 경우 예외를 발생시키는 것이 좋습니다.