2023. 11. 15. 23:16ㆍBook/이펙티브 자바
객체 생성과 파괴
!아이템4 목표!
사용자가 정적 멤버만 담은 유틸리티 클래스의 인스턴스를 만들어서 정적 메서드를 사용할 수 있다. 이는 문법적으로 이상하지 않지만 매우 불필요하고 사용자가 이 메서드가 인스턴스 메서드인지 static 한지 알 수 없기 때문에 좋지 않은 코드이기도 하다 이번 목표는 애초에 생성자를 이용해 인스턴스화 되는 것을 막는것이다.
들어가기 전 요약
- 정적 메서드만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 클래스가 아니다.
- 추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없다.
- private 생성자를 추가하며 클래스의 인스터스화를 막을 수 있다.
- 생상자에 주석으로 인스턴스화 불가한 이유를 설명하는 것이 좋다.
- 상속을 방지할 때도 같은 방법을 사용할 수 있다.
이따금 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있다. 객체 지향적이지 않은 방법이지만, 나름 쓰임새가 있다.
ex) 기본 타입 값을 모아놓은 java.lang.Math
public final class Math {
/**
* Don't let anyone instantiate this class.
*/
private Math() {}
/**
* The {@code double} value that is closer than any other to
* <i>e</i>, the base of the natural logarithms.
*/
public static final double E = 2.7182818284590452354;
/**
* The {@code double} value that is closer than any other to
* <i>pi</i>, the ratio of the circumference of a circle to its
* diameter.
*/
public static final double PI = 3.14159265358979323846;
/**
* Constant by which to multiply an angular value in degrees to obtain an
* angular value in radians.
*/
private static final double DEGREES_TO_RADIANS = 0.017453292519943295;
/**
* Constant by which to multiply an angular value in radians to obtain an
* angular value in degrees.
*/
private static final double RADIANS_TO_DEGREES = 57.29577951308232;
.
.
.
ex) 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드
public class Collections {
// Suppresses default constructor, ensuring non-instantiability.
private Collections() {
}
// Algorithms
private static final int BINARYSEARCH_THRESHOLD = 5000;
private static final int REVERSE_THRESHOLD = 18;
private static final int SHUFFLE_THRESHOLD = 5;
private static final int FILL_THRESHOLD = 25;
private static final int ROTATE_THRESHOLD = 100;
private static final int COPY_THRESHOLD = 10;
private static final int REPLACEALL_THRESHOLD = 11;
private static final int INDEXOFSUBLIST_THRESHOLD = 35;
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
.
.
.
정적 멤버만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 게 아니다. 하지만 생성자를 명시하지 않으면 자동으로 컴파일러가 기본 생성자를 만든다. 사용자는 이 생성자가 자동 생성된 것인지 구분할 수 없다.
new 연산자로 인스턴스를 생성시키지 못하니 추상클래스로 만들 수 있지 추상 클래스로 만드는 것으로 인스턴스화를 막을 수 없다. 하위 클래스를 만들어 인스턴스화 하면 그만이다. 이를 본 사용자가 상속해서 쓰라는 뜻으로 오해할 수 있으니 더 큰 문제다.
public abstract class UtilityClass {
public UtilityClass() {
System.out.println("Constructor");
}
public static String Hello() {
return "HELLO!";
}
}
=======================================================================================
public class DefaultUtilityClass extends UtilityClass{
public static void main(String[] args) {
DefaultUtilityClass utilityClass = new DefaultUtilityClass();
}
}
==> "Constructor"
다행히 생성자의 접근 지시자를 private으로 하면 간단하게 해결 할 수 있다.
public class UtilityClass {
/**
* Don't let anyone instantiate this class.
*/
private UtilityClass() {
throw new AssertionError();
}
public static String Hello() {
return "HELLO!";
}
}
사용자가 직관적으로 알 수 있게 주석으로 인스턴스화 할 수 없다고 달아두도록 하자. 또한 내부에서 실수로라도 생성자를 호출하지 않도록 AssertionError를 던져주자
'Book > 이펙티브 자바' 카테고리의 다른 글
Item6 - 불필요한 객체 생성을 피하라 (0) | 2023.11.17 |
---|---|
Item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2023.11.16 |
Item3 - 생성자나 열거 타입으로 싱글톤임을 보증하라. (1) | 2023.11.14 |
Item2 - 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2023.11.12 |
Item1 - 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2023.11.08 |