ITEM 4: Private Constructor

// Util이지만 생성자가 없음
public class ImageUtility {
    private static String IMAGE_DATE_FORMAT = "yyyyMMddHHmm";

    public static String makeImageFileNm(String imgFileNm) {
        return imgFileNm + "_" + new SimpleDateFormat(IMAGE_DATE_FORMAT).format(new Date());
    }
}

생성자를 명시하지 않으면 컴파일러가 자동으로 매개변수를 받지 않는 public 생성자를 만든다. 이때 사용자는 이 생성자가 자동으로 생성된 것인지 구분할 수 없으며,

// 다음과 같이 사용하기를 바랬으나,
ImageUtility.makeImageFileNm("test", ".png");
    
// 생성자를 생성해서 사용할 수도 있음
ImageUtility imageUtility = new ImageUtility();
String imageFileNm = imageUtility.makeImageFileNm("test", ".png");

이처럼 의도치 않게 인스턴스화할 수 있게된 클래스들도 발생한다.

// Util이지만 생성자가 없음
abstract class ImageUtility {
    private static String IMAGE_DATE_FORMAT = "yyyyMMddHHmm";

    public static String makeImageFileNm(String imgFileNm) {
        return imgFileNm + "_" + new SimpleDateFormat(IMAGE_DATE_FORMAT).format(new Date());
    }
}
public class ItemImageUtility extends ImageUtility {
  // ...
}
// 추상클래스이기 때문에 생성자 생성 불가
// ImageUtility imageUtility = new ImageUtility();

// 상속받은 클래스에서 생성자 호출 가능
ItemImageUtility itemImageUtility = new ItemImageUtility();

추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없으며, private 생성자를 추가하면 클래스의 인스턴스화를 막을 수 있다.

public class ImageUtility {
    // 기본 생성자가 만들어지는 것을 방어(인스턴스화 방지용)
    private ImageUtility(){
        throw new AssertionError();
    }
}

private 생성자이므로 클래스 외부에서는 접근할 수 없으며, 내부에서 실수로 생성자를 호출하는 경우에 대응하기 위해 AssrtionError 예외처리를 했다. 하지만, 생성자가 있는데 호출할 수 없는 것은 직관적이지 않으므로, 적절한 주석을 다는 것을 권장한다.

또한, private 생성자는 상속도 불가능하다. 모든 생성자는 상위 클래스의 생성자를 호출하게 되는데, 이를 private 선언으로 하위클래스가 상위 클래스의 생성자에 접근을 못해 상속이 불가능하다.

사용되는 Utility

java.util.Arrays

public class Arrays {

    /**
     * The minimum array length below which a parallel sorting
     * algorithm will not further partition the sorting task. Using
     * smaller sizes typically results in memory contention across
     * tasks that makes parallel speedups unlikely.
     */
    private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;

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

    /**
     * A comparator that implements the natural ordering of a group of
     * mutually comparable elements. May be used when a supplied
     * comparator is null. To simplify code-sharing within underlying
     * implementations, the compare method only declares type Object
     * for its second argument.
     *
     * Arrays class implementor's note: It is an empirical matter
     * whether ComparableTimSort offers any performance benefit over
     * TimSort used with this comparator.  If not, you are better off
     * deleting or bypassing ComparableTimSort.  There is currently no
     * empirical case for separating them for parallel sorting, so all
     * public Object parallelSort methods use the same comparator
     * based implementation.
     */
    static final class NaturalOrder implements Comparator<Object> {
        @SuppressWarnings("unchecked")
        public int compare(Object first, Object second) {
            return ((Comparable<Object>)first).compareTo(second);
        }
        static final NaturalOrder INSTANCE = new NaturalOrder();
    }
   ...

인스턴스화를 하지 않기 위해 private 생성자를 선언한 것을 볼 수 있으며, 배열 관련 메서드들을 모아 놓두었다.

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;

    /**
     * Returns the trigonometric sine of an angle.  Special cases:
     * <ul><li>If the argument is NaN or an infinity, then the
     * result is NaN.
     * <li>If the argument is zero, then the result is a zero with the
     * same sign as the argument.</ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result.
     * Results must be semi-monotonic.
     *
     * @param   a   an angle, in radians.
     * @return  the sine of the argument.
     */
    public static double sin(double a) {
        return StrictMath.sin(a); // default impl. delegates to StrictMath
    }

Math에 대한 기본 타입(PI, E)이나 관련 메서드들을 모아두었다.

java.util.Collection

특정 인터페이스르 구현하는 객체를 생성해주는 정적 메서드(팩터리)를 모아놓을 수 있다. (java8부터 이런 메서드를 인터페이스에 넣을 수 있음)

final 클래스와 관련 메서드

final class를 상속해서 하위 클래스에 메서드를 넣는 것은 불가능하므로, final 클래스와 관련 메서드들을 모아놓을때도 사용한다.

Last updated