Item4 : 인스턴스화를 막으려거든 private 생성자를 사용하라
종종 프로그래밍을 하다보면 정적 메서드와 정적 필드만을 담은 클래스를 본적이 있다. 이 책의 저자는 이러한 방식을 객체지향적 으로 사고하지 않는 방식이라며 얘기하지만 많은 이들이 유틸 형태의 클래스를 사용하곤 한다.
그 예로는 java.lang.Math , java.util.Arrays , java.utils.Collections등이 있다.
public 생성자
위의 나열한 클래스들의 생성자를 살펴보면 모두가 private 생성자를 사용하고 있다.
그 이유는 자바는 생성자를 명시하지 않으면, 컴파일시에 자동으로 public 생성자를 만들어 주기 때문이다.
이렇게 되면, 유틸 형태의 클래스의 인스턴스화가 가능하다. 그렇다면, 본래의 취지와는 다르게 사용되어진다.
public class NameUtils {
public static String name = "sup";
// 생성자를 명시하지 않아도, 컴파일시 자동으로 public 생성자가 만들어진다.
public NameUtils {}
public static String getName() {
return name;
}
}
종종 그래서 이를 간과하지 못한 예전의 코드들 중에 AnnotationElementUtils 와 같이 생성자를 비어 놓거나, public 형태로 선언되어 있는 클래스를 볼 수 있다. 또한 이를 막기위해 AnnotationBeanUtils 와 같은 예전 스프링 코드들을 추상클래스 형태로 선언해놓은 경우를 볼수도 있다.
추상클래스도 인스턴스화를 막을 수 없다.
추상 클래스는 인스턴스 생성이 불가능하다. 아직 완성되지 않은 클래스이기 때문이다. 그럼 정적 메소드 및 정적 필드를 담은 추상 클래스로 만들면 인스턴스화를 막을 수 있으니 해결된것이 아닐까? 아니다. 여기에는 문제가 따르게 된다. 추상클래스는 대부분 상속을 통해 추상 메소드등을 구현하게 되는데, 그러다보니 상속을 통하여 하위클래스를 만들어 인스턴스화하면 그만이다. 또한, 추상 클래스는 많은 사람들에게 상속을 통해 쓰라는 뜻으로 해석되어 질 수 있어 완벽한 문제의 해결을 할 수는 없다.
public abstract class AbsNameUtils {
public static String name = "sup";
public static String getName() {
return name;
}
}
public class customNameUtils extends AbsNameUtils{
}
public class Main {
public static void main(String[] args) {
// 이렇게 인스턴스 생성이 가능하다.
customNameUtils nameUtils = new customNameUtils();
// 다만 인스턴스를 통해 정적 메서드와 정적 필드에 접근할 수는 없다.
// 그러므로 아무 쓸모없는 인스턴스를 생성하게 되는 것이다.
}
}
pirvate 생성자를 선언하라
위의 문제를 완벽하게 해결할 수있는 방법은 private 생성자를 명시적으로 선언하는 것이다.
public class UtillityClass {
private UtillityClass {
throw new AssertionError();
}
}
위의 코드처럼 생성자를 선언해 준다. private 선언을 통해 외부에서 접근하지 못하게 한다. 뿐만아니라 내부에서 호출할 경우 AssertionError를 던져서 실수로라도 호출되지 않도록 한다. 또한 추상클래스에서 겪었던 상속의 문제도 해결할 수 있다. 기본적으로 상속한 클래스들은 자신들의 생성자를 호출할때 super()를 통해 상위 클래스의 생성자를 호출하도록 한다. 하지만, private으로 상위 클래스의 생성자를 선언할 경우엔 하위 클래스가 상위 클래스의 생성자에 접근할 방법이 없다.
출처
- Effective java 3rd edition
- 백기선님 유튜브
'Java' 카테고리의 다른 글
| [Effective java] Item6 : 불필요한 객체 생성을 피해라 (0) | 2021.04.18 |
|---|---|
| [Effective Java] Item5 : 자원을 직접 명시하지말고 의존객체 주입을 사용하라 (0) | 2021.04.10 |
| [Effective java] item3 : private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2021.03.28 |
| [Effective java] item2 : 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2021.03.01 |
| [Effective java] Item1 : 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2021.02.28 |
댓글