[Effective java] Item4. 인스턴스화를 막으려거든 private 생성자를 사용하라

Q_Hyun·2023년 10월 31일
0

Effective Java 스터디

목록 보기
2/3
post-thumbnail

Item4. 인스턴스화를 막으려거든 private 생성자를 사용하라

Item의 제목에서도 알 수 있듯이, 인스턴스를 생성하지 않는 가장 쉬운 방법은 private 생성자를 이용하는 것이다. private 생성자를 사용하게 된다면, 생성자를 호출하는 것으로 인스턴스를 생성할 수 없고, 상속이 불가능하다는 장점이 있다.

인스턴스화를 막으려고 하는 객체의 예시

인스턴스화를 막으려고 하는 객체는 Item3에서 많이 등장한 싱글톤 객체, 혹은 정적 클래스등이 있을 것이다. Java에서 쉽게 접할 수 있는 정적 클래스는 잘 알려진 MathCollections , Arrays등이 있다.

예시로 든 클래스들의 코드를 확인하면 아래와 같이 private 생성자 앞에서 주의를 주는 주석 작성한 것을 볼 수 있다.

public final class Math {
    /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}
}
public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }
}
public class Arrays {

    // Suppresses default constructor, ensuring non-instantiability.
    private Arrays() {}
}

그리고 Spring 에서 제공하는 여러 Utils 클래스들은 추상 클래스로 만들어놔서 인스턴스화를 막으려고 노력했다.

public abstract class StringUtils {
		...
}

하지만 이 두 방법 모두 인스턴스화를 완전히 막을 수는 없다.

먼저 private 생성자는 Item3 에서 확인한 것 처럼 reflection을 통해 인스턴스를 생성할 수 있고, 추상 클래스같은 경우는 상속을 받은 후 생성할 수 있기 때문이다.


public class Utils extends StringUtils {
}
    public static void main(String[] args){
        Utils utils = new Utils(); // StringUtils의 인스턴스가 생성되었음.
        utils.hasLength("123");
    }

이런 방법을 막고 싶으면 책에서 소개한 방법처럼 private 생성자 + exception 발생을 하면 해결할 수 있을 것이다.

다음 Calculator 클래스는

    private Calculator(){
        if(INSTANCE != null)
            throw new RuntimeException("생성자를 호출하지 마시오.");
    }
    
    ...
    
        public static void main(String[] args) throws Exception{
        Constructor<Calculator> cons = Calculator.class.getDeclaredConstructor();
        cons.setAccessible(true);
        cons.newInstance(); // 에러 발생 Caused by: java.lang.RuntimeException: 생성자를 호출하지 마시오.
    }
    

우선 reflection을 통한 생성은 막을 수 있었다.

그 다음은 상속을 통한 생성이다.


public class CalCalulator extends Calculator{

}

위와 같이 만든다고 해도 바로 컴파일 에러가 나기 때문에 이용할 수 없다.

private 생성자에서 예외 처리를 하는 것이 제일 확실한 인스턴스화를 막는 방법이지만, Java에서 사용하는 많은 정적 클래스들이 딱히 처리하지 않고, 주석을 남기는 것을 보면 정적 클래스들이 인스턴스 변수를 가지고 있지 않아서 추가적으로 생성해도 큰 문제가 없다고 생각하지 않았을까... 하는 생각이 든다.

0개의 댓글