반응형

ITEM 4 "인스턴스화를 막으려거든 private 생성자를 사용하라"

 

 

이 ITEM 을 확인하기 전에 위 백기선님의 Effective Java 해설 영상을 보는 것을 추천한다.

열심히 문어체로 정리하고 작성하지만, 구어체를 따라 올 전달력은 없는 것 같다. 열심히 예를 들어 설명해주셔서 덕분에 이해가 잘 됐다.

 

이번 장에서는 인스턴스를 막기 위해 private 생성자를 사용할 것을 권장하고 있다.

 

가끔 유틸 클래스처럼 정적 메서드와 정적 필드만 있는 클래스를 설계할 때가 있다. 유용한 메서드들을 한 곳에 모아둘 때 사용하곤 하는데 객체 생성 없이 사용할 수 있어 객체지향적 사고는 아니다. 이러한 클래스는 굳이 생성자가 필요하지 않기 때문에 생성자 생성을 제한하는 장치가 필요하다.

 

public abstract class UtilClass {
    public static String getName() { return "gold-egg"; }

    static class AnotherClass extends UtilClass {

    }

    public static void main(String[] args) {
        // abstract 추상 클래스에서는 인스턴스를 만들지 못 한다.
        UtilClass utilClass = new UtilClass();
        // 그 대신 상속해서 사용이 가능하다.
        AnotherClass anotherClass = new AnotherClass();
        // anotherClass.getName() 이 불가하다.

        UtilClass.getName();
    }
}

 

위 코드와 같이 생성자를 만들지 않으면 컴파일러가 자동으로 public 생성자를 만들어 준다. 사용자는 생성자가 자동 생성 된 것인지, 컴파일러가 만들어 준 것인지 알 수 없다. 이렇게 생성된 생성자를 사용할 경우, 잘못된 side effect 를 초래할 수 있다.

 

보통 Spring 프레임워크처럼 abstract 추상화 클래스를 선언하여 인스턴스 생성을 방지한다. 추상화 클래스를 상속하여 하위 클래스에서 인스턴스를 만들 수 있기 때문에 완벽한 금지 방법은 아니다. 또한, abstract 클래스는 원래 상속을 권장하기 위해 만들어진 클래스이므로 오해할 가능성이 있다. 그래서 책에서는 private 생성자를 명시하여 인스턴스화를 막는 것을 권장하고 있다.

 

클래스가 정말 정적 멤버(static 변수와 static 함수) 로만 이루어져 있다면 설령 자식 클래스로 인스턴스를 만든다고 하더라도 해당 static 함수를 사용할 수가 없다. anotherClass.getName() 부분이 불가한 것을 볼 수 있다. 인스턴스를 생성하더라도 못 쓰는 것이다. 아마도 Spring 프레임워크에서도 이 이유 때문에 abstract 클래스만 선언하여 사용하는 것으로 추정된다.

 

그럼에도 불구하고 하위 클래스에서도 생성자 생성을 금지하고 싶고 생성자를 호출하지 않게 하려면 아래와 같이 private 생성자를 만들고 접근 시 AssertionError 예외를 발생시키라고 권고하고 있다.

 

public class Test {
	private Test() { throw new AssertionError(); }
}

 

반응형

+ Recent posts