이번 포스팅은 Effective-java 3판 아이템 4에 관한 내용이며, Private 생성자에 대한 내용입니다. 책의 내용을 기반으로 작성되었지만 잘못된 부분이 있다면 댓글로 부탁드립니다.
1. 인스턴스화를 막는 방법
final 클래스
final 클래스는 인스턴스화가 되지 않을 뿐 아니라 상속도 지원하지 않는다. 따라서 final 클래스로 만들어진 클래스는 인스턴스화를 할 수 없게 된다.
public final class UtilityFinalClass {
public static void print() {
System.out.println("final class print()");
}
/* 불가능
static class AnotherClass extends UtilityFinalClass {
}*/
public static void main(String[] args) {
// UtilityFinalClass ifc = new UtilityFinalClass(); No create instance
UtilityFinalClass.print();
}
}
> Task :UtilityFinalClass.main()
final class print()
abstract 클래스
abstract 클래스도 인스턴스화를 할 수 없지만 상속은 가능하다.
public abstract class UtilityAbstractClass {
public static void print() {
System.out.println("abstract class print()");
}
static class AnotherClass extends UtilityAbstractClass {
}
public static void main(String[] args) {
// UtilityAbstractClass uac = new UtilityAbstractClass(); No Create Instance
AnotherClass ac = new AnotherClass();
UtilityAbstractClass.print();
}
}
상속이 가능하기는 하지만 상속받은 클래스를 인스턴스화 해도 별로 할 수 있는 거는 없다. 상속받은 클래스를 인스턴스화 해도 결국 부모 클래스에 존재하는 정적 팩토리 메서드에 접근하는 방법은 똑같다. 인스턴스로 만든 게 크게 의미가 없어지게 된다. (물론 위 코드에서의 상황이다)
private 생성자
private 생성자를 사용하게 되면 인스턴스화가 되지 않고 상속도 불가능하게 된다.
public class UtilityPrivateConstructorClass {
private UtilityPrivateConstructorClass() {
throw new AssertionError();
}
static class AnotherClass extends UtilityPrivateConstructorClass {
}
public static void print() {
System.out.println("UtilityPrivateConstructorClass()");
}
public static void main(String[] args) {
// No Create Instance
// UtilityPrivateConstructorClass up = new UtilityPrivateConstructorClass();
AnotherClass ac = new AnotherClass();
UtilityPrivateConstructorClass.print();
}
}
코드를 작성하게 되면 상속이 되는 것처럼 보이지만 실행하게 되면 아래와 같은 에러를 만나게 된다.
오류의 원인은 책에 나와 있는 내용을 확인하면 된다. 모든 생성자는 명시적이든 암묵적이든 상위 클래스의 생성자를 호출하게 되는데 이를 private 생성자로 선언했으니 하위 클래스가 상위 클래스의 생성자에 접근할 수 없게 되는 것이다.
2. 어떻게 사용될까
보통 Utility를 만들 때 사용하게 된다. 무분별한 인스턴스 생성을 막고 static 메소드로 만들어서 제공하는 형태이다. 아래 코드는 스프링 및 자바에서 사용하고 있는 Utility 클래스이다.
첫 번째 그림의 유틸은 abstract 클래스를 사용했음을 알 수 있고, 우리가 잘 알고 있는 Collections 클래스는 private 생성자를 사용했음을 알 수 있다. 인스턴화를 막는 결과는 동일하지만 위에서 살펴본 바와 같이 실제 사용하고 있는 코드에서도 인스턴스화를 막는 여러 방법을 사용하고 있음을 알 수 있다.
References
- Effective-java 3판, 조슈아 블로크 지음
- https://www.youtube.com/watch?v=A-t1T3_m15M, 백기선 님 유튜브
'dev. > Effective-Java' 카테고리의 다른 글
(아이템 5) 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.01.04 |
---|