-
객체 생성과 파괴 - 아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라Study/Effective Java 2022. 12. 12. 14:23
인스턴스화를 막으려거든 private 생성자를 사용하라
기본적으로 정적 메서드, 정적 필드만 담은 클래스는 때때로 유용하게 쓰일 수 있다. 사용하는 경우는 아래와 같이 크게 세 가지가 있다.
1. 기본 타입 값이나 배열 관련 메서드를 모은 클래스
예컨대, java.lang.Math와 java.util.Arrays처럼 기본 타입 값이나 배열 관련 메서드들을 모아놓을 수 있다.
public class Arrays { private Arrays() {} public static boolean isArray(Object o) { ... } public static Object[] asObjectArray(Object array) { ... } public sattic List<Object> asList(Object array) { ... } public static <T> boolean isNullOrEmpty(T[] array) { ... } ... }
java.util.Arrays의 코드를 살펴보면 위와 같다. 우리가 Arrays를 사용할 때를 생각해보면 Arrays arrays = new Arrays()로 생성하지 않고, Arrays.asList() 식으로 바로 사용한다. 내부 메서드를 살펴보니 전부 static으로 선언되어 있고, 생성자가 private로 선언된 것을 확인할 수 있다.
2. 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모은 클래스
java.util.Collections처럼 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모아놓을 수도 있다. java.util.Arrays와 마찬가지로 static으로만 메서드가 구성되어 있으며, private 생성자가 존재하는 것을 확인할 수 있다.
3. final 클래스와 관련된 메서드들을 모아놓은 경우
final 클래스를 상속해 하위 클래스를 만드는 것은 시스템의 파괴를 야기할 수 있기 때문에, final 클래스는 보안상의 이유로 상속을 금지시킨다.
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ... }
final 클래스의 대표적인 예로는 String 클래스가 있다.
@API(status = INTERNAL, since = "1.0") public final class StringUtils { private static final Pattern ISO_CONTROL_PATTERN = compileIsoControlPattern(); private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s"); static Pattern compileIsoControlPattern() { ... } private StringUtils() { /* no-op */ } public static boolean isBlank(String str) { ... } public static boolean isNotBlank(String str) { ... } public static boolean containsWhitespace(String str) { ... } ... }
String 클래스와 같은 final 클래스와 관련된 메서드들을 모아둔 클래스로는 JUnit에 존재하는 StringUtils 클래스가 있다. StringUtils 클래스 또한 메서드들이 static으로 선언되어 있기 때문에 바로 호출이 가능하다.
최종 정리
정적 메서드를 담은 클래스들은 보통 유틸리티 클래스로 사용하기 위해 생성된다. 유틸리티 클래스는 기본적으로 인스턴스로 만들어 쓰려고 설계한 것이 아니다.
또한, 아래와 같은 두 가지 의문점을 가질 수 있다.
1. 생성자를 명시하지 않으면 되지 않을까?
생성자를 명시하지 않으면 컴파일러가 자동으로 public 기본 생성자를 생성해준다. 따라서, 인스턴스화를 막기 위해서는 private 생성자를 명시해 주어야 한다.
2. 추상 클래스로 만들어서 인스턴스화를 막을 수 있을까?
추상 클래스는 인스턴스로 생성하는 것이 불가능하기 때문에, private 생성자 대신에 사용할 수 있지 않을까라고 생각할 수 있다. 하지만, 추상 클래스를 상속받은 하위 클래스를 생성하면 인스턴스화가 가능해진다.
또한, 추상 클래스는 보통 클래스들의 공통 필드와 메서드를 정의하는 목적으로 만들기 때문에 상속해서 사용하라는 의미로 오해할 수 있다.
출처
ㆍ 이펙티브 자바 Effective Java 3/E. 조슈아 블로크 저자(글) · 개앞맵시(이복연) 번역
728x90'Study > Effective Java' 카테고리의 다른 글
객체 생성과 파괴 - 아이템 6. 불필요한 객체 생성을 피하라 (0) 2022.12.12 객체 생성과 파괴 - 아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) 2022.12.12 객체 생성과 파괴 - 아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) 2022.12.12 객체 생성과 파괴 - 아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라 (0) 2022.12.12 객체 생성과 파괴 - 아이템 1. 생성자 대신 정적 팩토리 메서드를 고려하라 (0) 2022.12.08