static 메서드와 static 필드를 모아둔 클래스를 만든 경우 해당 클래스를 abstract로 만들어도 인스턴스를 만드는걸 막을 순 없다. 상속받아서 인스턴스를 만들 수 있기 때문에
그리고 아무런 생성자를 만들지 않은 경우 컴파일러가 기본적으로 아무 인자가 없는 public 생성자를 만들어 주기 때문에 이런 경우에도 인스턴스를 만들 수 있게 된다.
명시적으로 private 생성자를 추가해야 한다.
public class UtilityClass {
// Supress default constructor for noninstantiablity
private UtilityClass() {
throw new AssertionError();
}
}
예외는 꼭 필요하지 않지만 그렇게 하면 의도치 않게 생성자를 호출한 경우에 에러를 발생시킬 수 있고 private 생성자 덕분에 상속도 막을 수 있다.
생성자를 제공하지만 쓸 수 없기 때문에 직관에 어긋나는 점이 있는데, 그 때문에 위에 코드처럼 주석을 추가하는 것이 좋다.
부가적으로 상속도 막을 수 있다. 상속한 경우에 명시적이든 암묵적이든 상위 클래스의 생성자를 호출해야 하는데 이 클래스의 생성자가 private 이라 호출이 막혔기 때문에 상속을 할 수 없다.
과연 다른 유틸리티 클래스는 저 방식을 적용하고 있을까?
public abstract class AnnotatedElementUtils {
public AnnotatedElementUtils() {
}
~~~
}
public abstract class AnnotationConfigUtils {
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
public static final String CONFIGURATION_BEAN_NAME_GENERATOR = "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
/** @deprecated */
@Deprecated
public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalRequiredAnnotationProcessor";
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalCommonAnnotationProcessor";
public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME = "org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME = "org.springframework.context.event.internalEventListenerProcessor";
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME = "org.springframework.context.event.internalEventListenerFactory";
private static final boolean jsr250Present;
private static final boolean jpaPresent;
public AnnotationConfigUtils() {
}
~~~
}
대부분 만들어진 유틸클래스를 직접 살펴보면 아이템4에 나와있는 방식보단 abstract을 사용하고 private 생성자는 생성하지 않고 유틸클래스를 제공해주고 있다. 그 이유는 뭘까?
현실적으로 abstract로 만들어 상속을 받아 인스턴스를 생성해도 딱히 할 수 있는 작업이 없기 때문이다.