Generic κ³Ό Enum

1. Generic

1.1 νƒ€μž… νŒŒλΌλ―Έν„° 문법

Java 의 μ œλ„ˆλ¦­(Generic) 은 클래슀, μΈν„°νŽ˜μ΄μŠ€, λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•Œ νƒ€μž… νŒŒλΌλ―Έν„°(type parameter) λ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€μ–‘ν•œ νƒ€μž…μ— λŒ€ν•΄ λ™μž‘ν•˜λŠ” μΌλ°˜ν™”λœ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 있게 ν•΄μ£ΌλŠ” κΈ°λŠ₯μž„. νƒ€μž… νŒŒλΌλ―Έν„°λŠ” 보톡 <> κΊ½μ‡  κ΄„ν˜Έλ‘œ ν‘œν˜„ν•˜λ©°, ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€ 이름 λ’€ λ˜λŠ” λ©”μ„œλ“œ μ„ μ–ΈλΆ€μ—μ„œ λͺ…μ‹œν•¨. 예λ₯Ό λ“€μ–΄ JDK 의 List<E> μΈν„°νŽ˜μ΄μŠ€λŠ” μš”μ†Œμ˜ νƒ€μž…μ„ λ‚˜νƒ€λ‚΄λŠ” μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜ E λ₯Ό μ„ μ–Έν•˜λ©°, Iterator<E> 와 ν•¨κ»˜ μ œλ„€λ¦­μœΌλ‘œ μ •μ˜λ˜μ–΄ 있음. λ˜ν•œ Comparable<T> μΈν„°νŽ˜μ΄μŠ€ μ—­μ‹œ int compareTo(T o) 와 같이 νƒ€μž… νŒŒλΌλ―Έν„° T λ₯Ό μ‚¬μš©ν•¨. μ΄λŸ¬ν•œ <T> , <K, V> 와 같은 ν‘œκΈ°λ²•μ€ 각각 νƒ€μž… νŒŒλΌλ―Έν„°μ˜ 이름을 λ‚˜νƒ€λ‚΄λ©°, μ—¬λŸ¬ 개일 λ•Œ μ‰Όν‘œλ‘œ ꡬ뢄함.

μ œλ„€λ¦­ νƒ€μž…μ€ μ‚¬μš© μ‹œμ— ꡬ체적인 νƒ€μž… 인자λ₯Ό μ œκ³΅ν•˜μ—¬ νŒŒλΌλ―Έν„°ν™” 된 νƒ€μž… 을 λ§Œλ“¬. 예λ₯Ό λ“€μ–΄ List<String> 은 List<E> 의 E λ₯Ό String 으둜 μ§€μ •ν•œ νŒŒλΌλ―Έν„°ν™” νƒ€μž… μž„. ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€μ—μ„œλŠ” μ•„λž˜μ™€ 같이 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ„ μ–Έν•˜κ³  μ‚¬μš©ν•  수 있음. λ©”μ„œλ“œμ—λ„ μ œλ„€λ¦­μ„ μ μš©ν•  수 μžˆλŠ”λ°, λ©”μ„œλ“œ 리턴 νƒ€μž… μ•žμ— <T> 등을 λͺ…μ‹œν•˜μ—¬ μ œλ„€λ¦­ λ©”μ„œλ“œ 둜 선언함. (μƒμ„±μžμ—λ„ μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ„ μ–Έν•  수 있음.)

//μ œλ„€λ¦­ μΈν„°νŽ˜μ΄μŠ€ μ˜ˆμ‹œ : μž…λ ₯ νƒ€μž… Fλ₯Ό 좜λ ₯ νƒ€μž… T둜 λ³€ν™˜ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€
interface Converter<F, T> {
    T convert(F from);
}

// μ œλ„€λ¦­ 클래슀 μ˜ˆμ‹œ : 두 개의 값을 쌍으둜 λ³΄κ΄€ν•˜λŠ” 클래슀
class Pair<K, V> {
    private K key;
    private V value;
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    public K getKey() { return key; }
    public V getValue() { return value; }
}

// μ œλ„€λ¦­ λ©”μ„œλ“œ μ˜ˆμ‹œ : λ°°μ—΄μ˜ λͺ¨λ“  μ›μ†Œλ₯Ό 좜λ ₯ν•˜λŠ” λ©”μ„œλ“œ
class GenericUtils {
    public static <T> void printArray(T[] arr) {
        for(T element : arr) {
            System.out.println(element);
        }
    }
}

μœ„ μ½”λ“œμ—μ„œ Converter<F, T> λŠ” μΈν„°νŽ˜μ΄μŠ€μ˜ νƒ€μž… νŒŒλΌλ―Έν„° μ‚¬μš© μ˜ˆμ‹œμ΄λ©°, Pair<K, V> λŠ” ν΄λž˜μŠ€μ— 두 개의 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ„ μ–Έν•œ μ˜ˆμž„. GenericUtils.printArray λ©”μ„œλ“œλŠ” <T> λΌλŠ” νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ„ μ–Έν•˜μ—¬, λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ μž„μ˜μ˜ μ°Έμ‘°ν˜• νƒ€μž… 배열을 λ°›μ•„ 좜λ ₯ν•  수 μžˆλ„λ‘ ν•œ μ œλ„€λ¦­ λ©”μ„œλ“œ μž„. 이처럼 μ œλ„€λ¦­ νƒ€μž…μ΄λ‚˜ λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•  λ•Œ νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό νƒ€μž…μ΄ ν•„μš”ν•œ μœ„μΉ˜(ν•„λ“œ νƒ€μž…, λ©”μ„œλ“œ νŒŒλΌλ―Έν„° 및 λ³€ν™˜ νƒ€μž… λ“±) 에 μ‚¬μš©ν•  수 있음. μ‹€μ œ μ‚¬μš© μ‹œμ—λŠ” new Pair<String, Integer>("apple", 3) 처럼 νƒ€μž… 인자λ₯Ό ꡬ체적인 νƒ€μž…μœΌλ‘œ μ§€μ •ν•΄μ•Ό ν•˜λ©°, μ»΄νŒŒμΌλŸ¬λŠ” μ œλ„€λ¦­ νƒ€μž…μ„ κ²€μ‚¬ν•˜μ—¬ νƒ€μž… μ•ˆμ •μ„±μ„ 보μž₯ν•΄μ€Œ. (Java 7 λΆ€ν„°λŠ” μƒμ„±μž 호좜 μ‹œ νƒ€μž… 좔둠이 κ°€λŠ₯ν•΄ new Pair<>("apple", 3) 와 같이 μƒμ„±μžμͺ½ κΊ½μ‡ λ₯Ό μƒλž΅ν•˜λŠ” 닀이아λͺ¬λ“œ μ—°μ‚°μž 도 μ‚¬μš©ν•  수 있음.)

1.2 μ œμ•½ 쑰건과 bounded type(extends, 닀쀑 bound λ“±)

μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λŠ” μ œμ•½ 쑰건(bound) 을 μ§€μ •ν•˜μ—¬ μ‚¬μš©ν•  νƒ€μž…μ˜ μƒν•œ λ˜λŠ” ν•˜ν•œμ„ μ œν•œν•  수 있음. μƒν•œ 경계(Upper Bound) λ₯Ό μ§€μ •ν•  λ•ŒλŠ” extends ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•¨. 예λ₯Ό λ“€μ–΄ class NumberBox<T extends Number> 라고 μ„ μ–Έν•˜λ©΄ 이 클래슀의 νƒ€μž… νŒŒλΌλ―Έν„° T λŠ” Number 의 ν•˜μœ„ ν΄λž˜μŠ€λ“€λ§Œ ν—ˆμš©λ¨. μΈν„°νŽ˜μ΄μŠ€μ— λŒ€ν•œ μƒν•œλ„ extends 둜 ν‘œκΈ°ν•˜λ©°, μ—¬λŸ¬ 개의 μƒν•œμ„ μ§€μ •ν•˜λŠ” 닀쀑 bound 도 κ°€λŠ₯함. 예λ₯Ό λ“€μ–΄ <T extends Number & Comparable<T>> 라고 ν•˜λ©΄ T λŠ” Number λ₯Ό 상속받고 λ™μ‹œμ— Comparable<T> μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€μ—¬μ•Ό 함. 닀쀑 bound λ₯Ό μ§€μ •ν•  λ•ŒλŠ” ν΄λž˜μŠ€λŠ” ν•œ 번만 μ§€μ •ν•  수 있고(Number 같은 클래슀 μƒν•œμ„ λ‘˜ 이상 λ‚˜μ—΄ν•  수 μ—†μŒ), 클래슀 μƒν•œμ„ 제일 μ•žμ— 적어야 함. μΈν„°νŽ˜μ΄μŠ€ μƒν•œμ€ μ—¬λŸ¬ 개 μ§€μ •ν•  수 있으며, & 기호둜 연결함.

νƒ€μž… νŒŒλΌλ―Έν„°μ— μƒν•œμ„ μ§€μ •ν•˜λ©΄ κ·Έ νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” λ©€λ²„λ‚˜ λ©”μ„œλ“œκ°€ μ œν•œμ— 따라 달라짐. 예λ₯Ό λ“€μ–΄ <T extends Number> 둜 μ„ μ–Έλœ T λŠ” Number 의 λ©”μ„œλ“œλ“€(intValue() , doubleValue() λ“±) 을 μ‚¬μš©ν•  수 있음. 반면 ν•˜ν•œ 경계(Lower Bound) λŠ” νƒ€μž… νŒŒλΌλ―Έν„° μ„ μ–Έμ—μ„œλŠ” 직접 μ‚¬μš©ν•  수 μ—†κ³ (μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜μ— super λ₯Ό μ‚¬μš©ν•  μˆ˜λŠ” μ—†μŒ.) ν•˜ν•œμ€ 주둜 μ™€μΌλ“œμΉ΄λ“œμ—μ„œ μ‚¬μš©λ¨.(μ•„λž˜ μ™€μΌλ“œ μΉ΄λ“œ μ„Ήμ…˜ μ°Έμ‘°). μ •λ¦¬ν•˜λ©΄, νƒ€μž… λ³€μˆ˜μ˜ μ œν•œμ—λŠ” extends λ₯Ό μ‚¬μš©ν•˜κ³ , Java μ œλ„€λ¦­μ—μ„œλŠ” ν΄λž˜μŠ€λ“  μΈν„°νŽ˜μ΄μŠ€λ“  μ œν•œμ—λŠ” λͺ¨λ‘ extends λ₯Ό μ“΄λ‹€λŠ” 점에 μœ μ˜ν•΄μ•Όν•¨. (implements λ₯Ό μ“°μ§€ μ•ŠμœΌλ©°, super λŠ” νƒ€μž… λ³€μˆ˜ μ„ μ–Έμ—μ„œλŠ” ν—ˆμš©λ˜μ§€ μ•ŠμŒ)

λ‹€μŒμ€ νƒ€μž… νŒŒλΌλ―Έν„°μ— μƒν•œμ„ μ μš©ν•œ 클래슀 μ˜ˆμ‹œμž„. RestrictedBox λŠ” νƒ€μž… λ§€κ°œλ³€μˆ˜ T λ₯Ό Number 의 ν•˜μœ„μ΄λ©΄μ„œ Comparable<T> λ₯Ό κ΅¬ν˜„ν•œ νƒ€μž…μœΌλ‘œ μ œν•œν•˜κ³  있음. λ”°λΌμ„œ T λŠ” 숫자 νƒ€μž…(Number ν•˜μœ„) 이며 μ„œλ‘œ 비ꡐ κ°€λŠ₯ν•˜λ―€λ‘œ, 클래슀 λ‚΄λΆ€μ—μ„œ compareTo λ₯Ό μ‚¬μš©ν•  수 있음.

// 닀쀑 μƒν•œ(Bound) 을 κ°€μ§€λŠ” μ œλ„€λ¦­ 클래슀 μ˜ˆμ‹œ
class RestricedBox<T extends Number & Comparable<T>> {
    private T value;
    public RestrictedBox(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }
    // κ°’κ³Ό λ‹€λ₯Έ T κ°’μ˜ 크기λ₯Ό λΉ„κ΅ν•˜λŠ” λ©”μ„œλ“œ (Comparable<T> μ‚¬μš© κ°€λŠ₯)
    public int compareTo(T other) {
        return value.compareTo(other);
    }
}

μœ„ μ½”λ“œμ²˜λŸΌ <T extends μƒμœ„νƒ€μž…> ν˜•νƒœλ‘œ μ„ μ–Έν•˜λ©΄ TλŠ” ν•΄λ‹Ή μƒμœ„νƒ€μž…μœΌλ‘œ μ œν•œλ¨. λ§Œμ•½ T 에 μ—¬λŸ¬ 쑰건을 κ±Έκ³  μ‹Άλ‹€λ©΄ <T extends ClassA & InterfaceB & InterfaceC> 와 같이 선언함. 주의 : μƒν•œμ— ν΄λž˜μŠ€λŠ” ν•˜λ‚˜λ§Œ μ§€μ • κ°€λŠ₯ν•˜λ©°, ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν•¨κ»˜ μ§€μ •ν–ˆλ‹€λ©΄ 클래슀 μƒν•œμ„ λ¨Όμ € λͺ…μ‹œν•΄μ•Ό 함.

1.3 μ™€μΌλ“œμΉ΄λ“œ(?, ? extends, ? super)

μ œλ„€λ¦­μ„ μ‚¬μš©ν•˜λ‹€ 보면, ꡬ체적인 νƒ€μž… 인자λ₯Ό μ§€μ •ν•˜μ§€ μ•Šκ³ , μ™€μΌλ“œμΉ΄λ“œ(?) 둜 ν‘œν˜„ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ 있음. μ™€μΌλ“œμΉ΄λ“œλŠ” μ œλ„€λ¦­ νƒ€μž…μ„ μ‚¬μš©ν•  λ•Œ κ·Έ νƒ€μž…μ΄ μ–΄λ–€ νƒ€μž…μΈμ§€ ν™•μ‹€ν•˜μ§€ μ•Šκ±°λ‚˜ 상관 μ—†μŒ 을 λ‚˜νƒ€λ‚΄λŠ” μš©λ„λ‘œ, ? λ‹¨λ…μœΌλ‘œ λ˜λŠ” extends , super ν‚€μ›Œλ“œμ™€ ν•¨κ»˜ μ‚¬μš©ν•¨.

  • ? (λ¬΄μ œν•œ μ™€μΌλ“œ μΉ΄λ“œ) : νŠΉμ • μ œν•œ 없이 "μ–΄λ–€ νƒ€μž…μ΄λ“  될 수 μžˆλ‹€." λŠ” 의미λ₯Ό 가짐. 예λ₯Ό λ“€μ–΄ List<?> λŠ” "아무 νƒ€μž…μ˜ 객체λ₯Ό 담을 수 μžˆλŠ” 리슀트" λ₯Ό λœ»ν•¨. List<?> λŠ” 사싀상 List<? extends Object> 와 동일함. μ™€μΌλ“œμΉ΄λ“œλ₯Ό μ œν•œ 없이 μ‚¬μš©ν•  λ•ŒλŠ” 주둜 λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ νƒ€μž…μ— μ˜μ‘΄ν•˜μ§€ μ•ŠλŠ” λ‘œμ§μ„ μ²˜λ¦¬ν•˜κ±°λ‚˜, μ œλ„€λ¦­ νƒ€μž… κ°„μ˜ 관계λ₯Ό κ°•μ œν•  ν•„μš”κ°€ 없을 λ•Œμž„. λ¬΄μ œν•œ μ™€μΌλ“œμΉ΄λ“œμΌ 경우 데이터λ₯Ό μΆ”κ°€ μ‚½μž…ν•  수 μ—†κ³  (νƒ€μž…μ„ μ•Œ 수 μ—†μœΌλ―€λ‘œ μ»΄νŒŒμΌλŸ¬κ°€ λ§‰μŒ), κ°€μ Έμ˜¬ λ•ŒλŠ” Object νƒ€μž…μœΌλ‘œλ§Œ 얻을 수 있음.

  • ? extends T (μƒν•œμ΄ μžˆλŠ” μ™€μΌλ“œμΉ΄λ“œ) : ꡬ체적인 νƒ€μž… μΈμžλŠ” λͺ¨λ₯΄μ§€λ§Œ μ–΄λ–€ νŠΉμ • νƒ€μž… T 의 ν•˜μœ„ νƒ€μž… 으둜 μ œν•œν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•¨. ? extends T μ™€μΌλ“œ μΉ΄λ“œλ₯Ό μ‚¬μš©ν•œ μ œλ„€λ¦­ νƒ€μž…μ€ ν•΄λ‹Ή νƒ€μž…μ—μ„œ 값을 κΊΌλ‚΄(read) λ³Ό λ•Œ μ•ˆμ „ν•˜κ²Œ T 둜 μ·¨κΈ‰ ν•  수 μžˆλ‹€λŠ” μž₯점이 있음. 예λ₯Ό λ“€μ–΄ List<? extends Number> λŠ” Number 의 ν•˜μœ„ νƒ€μž…λ“€λ‘œ κ΅¬μ„±λœ 리슀트λ₯Ό 가리킬 수 μžˆλŠ”λ°, 이 λ¦¬μŠ€νŠΈμ—μ„œ μš”μ†Œλ₯Ό κΊΌλ‚΄λ©΄ 항상 Number 둜 받아듀일 수 있음. κ·ΈλŸ¬λ‚˜ μ»΄νŒŒμΌλŸ¬λŠ” λ¦¬μŠ€νŠΈμ— μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό μΆ”κ°€ν•˜λŠ” 것은 λ§‰μŒ. μ™œλƒν•˜λ©΄ List<? extends Number> κ°€ κ°€λ¦¬ν‚€λŠ” μ‹€μ œ λ¦¬μŠ€νŠΈκ°€ List<Integer> 인지 List<Double> 인지 μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ—, μž„μ˜μ˜ Number λ₯Ό λ„£λŠ” μž‘μ—…μ€ νƒ€μž… 뢈일치 μœ„ν—˜μ΄ 있기 λ•Œλ¬Έμž„. λ”°λΌμ„œ ? extends T λ₯Ό μ“°λ©΄ 읽기 μ „μš© 으둜 μ‚¬μš©ν•˜κ²Œ 되고, μΆ”κ°€ μ‚½μž…μ€ ν•  수 μ—†μŒ.(null μΆ”κ°€ μ •λ„λ§Œ μ˜ˆμ™Έμ μœΌλ‘œ ν—ˆμš©λ˜μ§€λ§Œ νŠΉλ³„ν•œ 경우λ₯Ό μ œμ™Έν•˜λ©΄ ν™œμš©λ˜μ§€ μ•ŠμŒ)

  • ? super T ( ν•˜ν•œμ΄ μžˆλŠ” μ™€μΌλ“œ μΉ΄λ“œ ) : μ–΄λ–€ νŠΉμ • νƒ€μž… T 의 μƒμœ„ νƒ€μž… 으둜 μ œν•œν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•¨. ? super T μ™€μΌλ“œμΉ΄λ“œλ₯Ό μ‚¬μš©ν•œ μ œλ„€λ¦­ νƒ€μž…μ€ ν•΄λ‹Ή νƒ€μž…μ— 값을 μΆ”κ°€(write) ν•  λ•Œ μ•ˆμ „ν•˜κ²Œ T νƒ€μž…μœΌλ‘œ 넣을 수 μžˆλ‹€ λŠ” νŠΉμ§•μ΄ 있음. 예λ₯Ό λ“€μ–΄ List<? super Integer> λŠ” Integer 의 μƒμœ„ νƒ€μž… 리슀트(List<Number> , List<Object> λ“±)λ₯Ό 가리킬 수 μžˆλŠ”λ°, 이 λ¦¬μŠ€νŠΈμ— Integer 값을 μΆ”κ°€ν•˜λŠ” 것은 νƒ€μž… μ•ˆμ „ν•¨. μ™œλƒν•˜λ©΄ μ‹€μ œ λ¦¬μŠ€νŠΈκ°€ Number λ‚˜ Object νƒ€μž…μ˜ 리슀트라면 Integer λŠ” κ·Έ ν•˜μœ„λ‘œμ„œ μ €μž₯될 수 있기 λ•Œλ¬Έμž„. ν•˜μ§€λ§Œ λ°˜λŒ€λ‘œ κΊΌλ‚΄μ˜¬ λ•ŒλŠ” νƒ€μž…μ΄ λͺ¨ν˜Έν•˜λ―€λ‘œ Object 둜만 얻을 수 있음. λ”°λΌμ„œ ? super T λ₯Ό μ“°λ©΄ μ“°κΈ° μ „μš© λͺ©μ μœΌλ‘œ ν™œμš©λ˜λ©°, μš”μ†Œλ₯Ό μ½μ–΄μ„œ μ‚¬μš©ν•  λ•ŒλŠ” μ¦‰μ‹œ T νƒ€μž…μž„μ„ 보μž₯ν•˜μ§€ λͺ»ν•¨.(ν•„μš”ν•˜λ‹€λ©΄ μΊμŠ€νŒ…μ΄ ν•„μš”ν•¨.)

μ΄λŸ¬ν•œ μ™€μΌλ“œμΉ΄λ“œ μ‚¬μš© νŒ¨ν„΄μ„ μš”μ•½ν•˜λŠ” 유λͺ…ν•œ 원칙이 PECS(Producer Extends, Consumer Super) μž„. 즉, 데이터λ₯Ό 생산(제곡) ν•˜λŠ” λ§€κ°œλ³€μˆ˜λŠ” ? extends 둜 λ°›κ³ , μ†ŒλΉ„(μΆ”κ°€ μ €μž₯) ν•˜λŠ” λ§€κ°œλ³€μˆ˜λŠ” ? super 둜 λ°›μœΌλΌλŠ” κ°€μ΄λ“œλΌμΈμž„. λ§Œμ•½ ν•œ λ³€μˆ˜μ—μ„œ 데이터 μž…λ ₯κ³Ό 좜λ ₯ 역할을 λͺ¨λ‘ ν•΄μ•Ό ν•œλ‹€λ©΄ μ™€μΌλ“œμΉ΄λ“œλ₯Ό μ“°μ§€ μ•Šκ³  νƒ€μž… νŒŒλΌλ―Έν„° 자체λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ•ˆμ „ν•¨.

μ™€μΌλ“œμΉ΄λ“œ ν™œμš© μš”μ•½ :

  • List<? extends T> : T 의 ν•˜μœ„ νƒ€μž…λ“€μ„ λ‹΄λŠ” 리슀트. 읽기 λŠ” T 둜 μ•ˆμ „ν•˜κ²Œ κ°€λŠ₯, μ“°κΈ° (μΆ”κ°€)λŠ” λΆˆκ°€λŠ₯.(Producer μš©λ„)

  • List<? super T> : T 의 μƒμœ„ νƒ€μž…λ“€μ„ λ‹΄λŠ” 리슀트. 읽기 μ‹œμ—λŠ” Object 둜만 νšλ“, μ“°κΈ° λŠ” T (λ˜λŠ” κ·Έ ν•˜μœ„) 객체 μΆ”κ°€ κ°€λŠ₯.(Comsumer μš©λ„)

  • List<?> : λΆˆνŠΉμ • νƒ€μž…μ˜ 리슀트. Object 이외 ꡬ체적 νƒ€μž…μœΌλ‘œ 읽기 λΆˆκ°€, μ“°κΈ° λΆˆκ°€.(List<? extends Object> 와 동일)

μ™€μΌλ“œ μΉ΄λ“œμ˜ λ™μž‘ 예제

μ•„λž˜ μ½”λ“œμ—μ„œ ? extends Number 와 ? super Integer 리슀트의 차이λ₯Ό λ³΄μ—¬μ€Œ.

List<Integer> intList = Arrays.asList(1, 2, 3);
List<? extends Number> numList = intList;
Number num = numList.get(0);        // OK : Number 둜 읽기
// numList.add(4);                  // 컴파일 였λ₯˜ : extends μ™€μΌλ“œμΉ΄λ“œλŠ” μΆ”κ°€ λΆˆκ°€

List<Object> objList = new ArrayList<>();
List<? super Integer> superList = objList;
superList.add(100);                // OK : Integer μΆ”κ°€ κ°€λŠ₯
Object obj = superList.get(0);     // OK : Ojbect 둜 읽기( Integer μž„μ„ μ•Œ 수 μ—†μŒ)

μœ„ μ½”λ“œμ—μ„œ numList λŠ” Integer 리슀트λ₯Ό λ°›μ•˜μ§€λ§Œ List<? extends Number> 둜 μ„ μ–Έλ˜μ—ˆκΈ° λ•Œλ¬Έμ— Number 둜 κ°’ 읽기(get ) κ°€ κ°€λŠ₯함. κ·ΈλŸ¬λ‚˜ add λ©”μ„œλ“œλŠ” 컴파일 μ—λŸ¬μΈ 것을 λ³Ό 수 있음. λ°˜λŒ€λ‘œ superList λŠ” Object 리슀트λ₯Ό κ°€λ¦¬ν‚€μ§€λ§Œ List<? super Integer> νƒ€μž…μœΌλ‘œ μ„ μ–Έλ˜μ—ˆκΈ° λ•Œλ¬Έμ— Integer 값을 μΆ”κ°€(add ) ν•˜λŠ” 것은 ν—ˆμš©λ¨. λ‹€λ§Œ get 으둜 κ°€μ Έμ˜¨ 값은 Object νƒ€μž…μœΌλ‘œλ§Œ 얻어짐. 이처럼 μ™€μΌλ“œμΉ΄λ“œλŠ” μ œλ„€λ¦­ νƒ€μž…μ„ 보닀 μœ μ—°ν•˜κ²Œ λ‹€λ£¨κ²Œ ν•΄μ£Όμ§€λ§Œ, extends 와 super 에 따라 읽기/μ“°κΈ°μ˜ μ œμ•½μ΄ λ‹€λ₯΄λ―€λ‘œ μœ„ 원칙에 따라 μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŒ.

1.4 νƒ€μž… μ†Œκ±°(Type Erasure)와 μ œλ„€λ¦­μ˜ ν•œκ³„

Java 의 μ œλ„€λ¦­μ€ 컴파일 νƒ€μž„ μ—λ§Œ μœ νš¨ν•˜κ³  λŸ°νƒ€μž„μ—λŠ” νƒ€μž… 정보가 μ†Œκ±° 됨. 이λ₯Ό νƒ€μž… μ†Œκ±°(type erasure) 라고 λΆ€λ₯΄λ©°, Java μ»΄νŒŒμΌλŸ¬λŠ” μ œλ„€λ¦­μ„ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ 컴파일 μ‹œ λ‹€μŒκ³Ό 같은 μž‘μ—…μ„ μˆ˜ν–‰ν•¨.

  • λͺ¨λ“  μ œλ„€λ¦­ νƒ€μž… λ³€μˆ˜λ“€μ„ κ·Έ μƒν•œ 경계 νƒ€μž…μ΄λ‚˜ Object 둜 λŒ€μΉ˜ 함.(μƒν•œ 경계가 μ—†λ‹€λ©΄ Object 둜 μΉ˜ν™˜). 예λ₯Ό λ“€μ–΄ μ»΄νŒŒμΌλŸ¬λŠ” List<String> κ³Ό List<Integer> λ₯Ό λ‘˜ λ‹€ λ‚΄λΆ€μ μœΌλ‘œλŠ” λ‹¨μˆœν•œ List (ν˜Ήμ€ List<Object> ) 둜 간주함.

  • μ œλ„€λ¦­μœΌλ‘œ 인해 ν•„μš”ν•΄μ§„ νƒ€μž… μΊμŠ€νŒ… μ½”λ“œλ₯Ό 적절히 μ‚½μž…ν•˜μ—¬ νƒ€μž… μ•ˆμ •μ„±μ„ μœ μ§€ν•¨.

  • μ œλ„€λ¦­ νƒ€μž…μ„ μƒμ†ν•˜μ—¬ ν•˜μœ„μ—μ„œ ν˜•λ³€ν™˜λ˜λŠ” 경우 bridge method 등을 μƒμ„±ν•˜μ—¬ λ‹€ν˜•μ„±μ΄ μ œλŒ€λ‘œ μœ μ§€λ˜λ„λ‘ 함.

κ·Έ κ²°κ³Ό λ°”μ΄νŠΈμ½”λ“œμ—λŠ” μ œλ„€λ¦­ νƒ€μž… 정보가 λ“€μ–΄κ°€μ§€ μ•ŠμœΌλ©° , λŸ°νƒ€μž„μ—λŠ” μ œλ„€λ¦­ νƒ€μž… μΈμžμ— λ”°λ₯Έ λ³„λ„μ˜ ν΄λž˜μŠ€κ°€ μƒμ„±λ˜μ§€ μ•ŠμŒ. λ”°λΌμ„œ μ œλ„€λ¦­ 자체둜 μΈν•œ λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œλŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ . μ΄λŠ” C++의 ν…œν”Œλ¦Ώκ³Ό 달리, Java 의 μ œλ„€λ¦­μ€ 컴파일 μ‹œμ—λ§Œ λ™μž‘ν•˜κ³  λŸ°νƒ€μž„μ— 영ν–₯이 μ—†λ‹€λŠ” μ€‘μš”ν•œ νŠΉμ§•μž„.

ν•˜μ§€λ§Œ νƒ€μž… μ†Œκ±°λ‘œ 인해 λͺ‡ κ°€μ§€ μ œμ•½μ‚¬ν•­κ³Ό 주의점 이 생김.

  • instanceof 와 μΊμŠ€νŒ…μ˜ μ œν•œ : λŸ°νƒ€μž„μ—λŠ” μ œλ„€λ¦­ νƒ€μž… 인자 정보가 μ§€μ›Œμ§€λ―€λ‘œ, νŠΉμ • μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œμ˜ instanceof κ²€μ‚¬λŠ” λΆˆκ°€λŠ₯함. 예λ₯Ό λ“€μ–΄ obj instanceof List<String> 와 같은 μ½”λ“œλŠ” 컴파일 였λ₯˜μž„. μ΄λŠ” JVM 이 λŸ°νƒ€μž„μ— List<String> κ³Ό List<Integer> λ₯Ό ꡬ뢄할 수 μ—†κΈ° λ•Œλ¬Έμž„. μ‹€μ œλ‘œ new ArrayList<String>() 둜 λ§Œλ“  λ¦¬μŠ€νŠΈμ™€ new ArrayList<Integer>() 둜 λ§Œλ“  리슀트의 ν΄λž˜μŠ€νƒ€μž…μ„ 좜λ ₯해보면 λ‘˜ λ‹€ java.util.ArrayList 둜 λ‚˜νƒ€λ‚¨. 예λ₯Ό λ“€μ–΄:

List<String> listA = new ArrayList<>();
List<Integer> listB = new ArrayList<>();
System.out.println(listA.getClass() == listB.getClass()); // true(λ‘˜λ‹€ ArrayList)

μœ„ κ²°κ³Όμ—μ„œ 두 리슀트의 ν΄λž˜μŠ€κ°€ 동일(ture ) 함을 확인할 수 있음. 즉, λŸ°νƒ€μž„μ—λŠ” μ œλ„€λ¦­ νƒ€μž… 인자의 ꡬ뢄이 μ—†λŠ” κ²ƒμž„. λ”°λΌμ„œ, instanceof ArrayList<String> 같은 μ½”λ“œλŠ” μ˜λ―Έκ°€ μ—†μœΌλ©° μ»΄νŒŒμΌλŸ¬κ°€ 이λ₯Ό κΈˆμ§€ν•¨. instanceof λŠ” 였직 μ›μ‹œ(raw) νƒ€μž…μ΄λ‚˜ ν•œμ •λ˜μ§€ μ•Šμ€ μ™€μΌλ“œμΉ΄λ“œ(ArrayList<?> ) 등에 λŒ€ν•΄μ„œλ§Œ μ‚¬μš©ν•  수 있음.

  • μ œλ„€λ¦­ νƒ€μž…μ˜ λ°°μ—΄ 생성 λΆˆκ°€ : μ œλ„€λ¦­ νƒ€μž… μ •λ³΄λŠ” λŸ°νƒ€μž„μ— μ†Œκ±°λ˜λ―€λ‘œ, μ œλ„€λ¦­ νƒ€μž…μ˜ λ°°μ—΄ 을 생성할 수 μ—†μŒ. 예λ₯Ό λ“€μ–΄ List<String>[] array = new List<String>[10]; κ³Ό 같은 μ½”λ“œλ„ 컴파일 μ‹œ 였λ₯˜κ°€ λ°œμƒν•¨. μ΄λŠ” 배열이 λŸ°νƒ€μž„μ— μžμ‹ μ΄ λ‹΄λŠ” μ›μ†Œμ˜ νƒ€μž…μ„ ν™•μΈν•˜λŠ” νŠΉμ§•(곡변성) 이 μžˆλŠ”λ°, μ œλ‹ˆλ¦­ νƒ€μž…μ˜ λ°°μ—΄μ˜ 경우 이ㅏλ₯Ό 검사할 방법이 μ—†κΈ° λ•Œλ¬Έμž„. λ§Œμ•½ μ œλ„€λ¦­ 배열이 ν—ˆμš©λœλ‹€λ©΄, λ°°μ—΄μ˜ νƒ€μž… μ•ˆμ •μ„±μ„ 깨뜨릴 수 μžˆλŠ” 상황이 생겨도 λŸ°νƒ€μž„μ— μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚€μ§€ λͺ»ν•˜κ³  잘λͺ»λœ μΊμŠ€νŒ… λ¬Έμ œκ°€ λ°œμƒν•  수 있음. μ΄λŸ¬ν•œ 이유둜 Java μ—μ„œλŠ” 비검증(unchecked) 캐슀트 κ²½κ³  λ₯Ό κ°μˆ˜ν•˜κ³  Object 배열을 μƒμ„±ν•œ λ’€ μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ μΊμŠ€νŒ…ν•˜λŠ” 우회 방법을 μ“°μ§€ μ•ŠλŠ” ν•œ, 직접적인 μ œλ„€λ¦­ λ°°μ—΄ 생성은 κΈˆμ§€λ¨.

  • 기타 μ œν•œ : μ œλ„€λ¦­ νƒ€μž…μ˜ 정보가 μ†Œκ±°λ˜λ―€λ‘œ, 클래슀의 static ν•„λ“œμ—λŠ” νƒ€μž… λ³€μˆ˜ μ‚¬μš©μ΄ λΆˆκ°€λŠ₯ 함. static ν•„λ“œλŠ” 클래슀 μˆ˜μ€€μ—μ„œ 단 ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜λŠ”λ°, νƒ€μž… λ§€κ°œλ³€μˆ˜λŠ” μΈμŠ€ν„΄μŠ€λ³„λ‘œ λ‹¬λ¦¬μ§ˆ 수 μžˆμœΌλ―€λ‘œ λͺ¨μˆœμ΄ 생기기 λ•Œλ¬Έμž„. λ˜ν•œ μ˜ˆμ™Έ 클래슀(Throwable ν•˜μœ„)에 μ œλ„€λ¦­μ„ 적용 ν•  수 μ—†μœΌλ©°, μ œλ„€λ¦­ νƒ€μž…μ„ throws μ ˆμ— μ‚¬μš©ν•˜κ±°λ‚˜ catch μ ˆμ— νƒ€μž… λ³€μˆ˜λ‘œ μ˜ˆμ™Έλ₯Ό μž‘λŠ” 것 도 μ œν•œλ¨. λ©”μ„œλ“œ μ˜€λ²„λ‘œλ”© μ‹œμ—λ„ νƒ€μž… μ†Œκ±° κ²°κ³Ό μ‹œκ·Έλ‹ˆμ²˜κ°€ κ°™μ•„μ§€λŠ” 경우 μ˜€λ²„λ‘œλ”©μ΄ μ„±λ¦½λ˜μ§€ μ•ŠμŒ.( 예λ₯Ό λ“€μ–΄, void method(List<String> x) 와 void method(List<Integer> x) λŠ” λ‘˜ λ‹€ void method(List x) 둜 μ†Œκ±°λ˜λ―€λ‘œ λ™μ‹œμ— μ •μ˜ν•  수 μ—†μŒ).

μš”μ•½ν•˜λ©΄, Java 의 μ œλ„€λ¦­μ€ μ»΄νŒŒμΌλŸ¬κ°€ κ°•ν•œ νƒ€μž… 검사λ₯Ό ν•΄μ£ΌλŠ” 문법적인 μž₯치이며, λŸ°νƒ€μž„μ—λŠ” λͺ¨λ“  μ œλ„€λ¦­ νƒ€μž…μ΄ μ›μ‹œ νƒ€μž…(raw type) 으둜 μ·¨κΈ‰ 됨. μ΄λŸ¬ν•œ κ΅¬ν˜„μœΌλ‘œ μ„±λŠ₯상 이점이 μžˆμ§€λ§Œ, μœ„μ™€ 같은 ν•˜κ³„μ— μœ μ˜ν•΄μ•„ 함. 특히 instanceof λ‚˜ λ°°μ—΄ 생성 μ‹œμ—λŠ” μ œλ„€λ¦­ νƒ€μž… 정보λ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€λŠ” 점을 κΈ°μ–΅ν•΄μ•Ό 함.

List<String> list = new ArrayList<>();
// if (list instanceof ArrayList<String>) { ... }  // 컴파일 였λ₯˜: μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ instanceof λΆˆκ°€

// List<String>[] listArray = new List<String>[5]; // 컴파일 였λ₯˜: μ œλ„€λ¦­ λ°°μ—΄ 생성 λΆˆκ°€

// (주의) μ œλ„€λ¦­ νƒ€μž…μ˜ λŸ°νƒ€μž„ νƒ€μž… 확인은 λΆˆκ°€λŠ₯ 
System.out.println(list.getClass());            // 좜λ ₯ 예: class java.util.ArrayList  (νƒ€μž… 인자 뢈λͺ…)

μœ„ μ½”λ“œμ—μ„œ 보듯이, instanceof ArrayList<String> 같은 κ²€μ‚¬λŠ” ν—ˆμš©λ˜μ§€ μ•ŠμœΌλ©° μ œλ„€λ¦­ λ°°μ—΄ 생성도 컴파일이 λ§‰μŒ. λ§ˆμ§€λ§‰ 좜λ ₯ κ²°κ³Όμ—μ„œ list 의 μ‹€μ œ 클래슀 νƒ€μž…μ€ ArrayList 둜만 λ‚˜νƒ€λ‚˜κ³ , <String> μ •λ³΄λŠ” 확인할 수 μ—†μŒ. 이처럼 μ œλ„€λ¦­μ€ μ˜€λ‘œμ§€ 컴파일 μ‹œμ μ˜ νƒ€μž… μ•ˆμ •μ„±μ„ μœ„ν•œ 도ꡬ 이며, λŸ°νƒ€μž„μ—λŠ” νƒ€μž…μ΄ μ§€μ›Œμ§„λ‹€λŠ” 사싀을 이해해야함.(ν•„μš”ν•˜λ‹€λ©΄ λ¦¬ν”Œλ ‰μ…˜ λ“±μ˜ κΈ°λ²•μœΌλ‘œ 일뢀 μ œλ„€λ¦­ νƒ€μž… 정보 (Class<T> 인수 λ“±) λ₯Ό λ‹€λ£° 수 μžˆμ§€λ§Œ, 일반적인 μƒν™©μ—μ„œλŠ” νƒ€μž… μ†Œκ±°λ‘œ 인해 μ œλ„€λ¦­ νƒ€μž… μΈμžλŠ” λŸ°νƒ€μž„μ— ν™œμš©λ˜μ§€ μ•ŠμŒ.)

2. μ—΄κ±°ν˜•(Enum)

2.1 κΈ°λ³Έ 문법과 μ‚¬μš© 예

Java 의 μ—΄κ±°ν˜•(enum) 은 λͺ‡ κ°€μ§€ μƒμˆ˜λ“€μ˜ μ§‘ν•© 을 ν•˜λ‚˜μ˜ νƒ€μž…μœΌλ‘œ ν‘œν˜„ν•˜λŠ” νŠΉλ³„ν•œ ν΄λž˜μŠ€μž„. enum 은 ν΄λž˜μŠ€μ™€ μœ μ‚¬ν•˜κ²Œ μ •μ˜ν•˜μ§€λ§Œ, 미리 μ •ν•΄μ§„ μ—¬λŸ¬ μƒμˆ˜(constants) λ₯Ό λ‚˜μ—΄ν•˜μ—¬ κ·Έ κ°’λ“€λ§Œ κ°€μ§ˆ 수 μžˆλ„λ‘ 함. μ„ μ–Έ 문법은 enum μ—΄κ±°ν˜• 이름 { μƒμˆ˜1, μƒμˆ˜2, ... } ν˜•νƒœλ‘œ μ‚¬μš©ν•¨. 예λ₯Ό λ“€μ–΄ μš”μΌμ„ λ‚˜νƒ€λ‚΄λŠ” μ—΄κ±°ν˜•μ„ λ‹€μŒκ³Ό 같이 μ •μ˜ν•  수 있음.

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

μ΄λ ‡κ²Œ μ—΄κ±°λœ 이름듀이 Day enum νƒ€μž…μ˜ μƒμˆ˜ 듀이며, 각각 Day.SUNDAY , Day.MONDAY 처럼 μ‚¬μš©ν•  수 있음.

사싀 enum 으둜 μ„ μ–Έλœ 각 μƒμˆ˜λŠ” ν•΄λ‹Ή enum νƒ€μž…μ˜ public static final 객체 둜 간주됨. Enum νƒ€μž…μ€ λ‚΄λΆ€μ μœΌλ‘œ java.lang.Enum 클래슀λ₯Ό μƒμ†ν•˜λ©°, λ‹€λ₯Έ 클래슀λ₯Ό 상속할 μˆ˜λŠ” μ—†μŒ.(μžλ°” μ–Έμ–΄μ—μ„œ 닀쀑 상속을 μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ, 이미 Enum 을 μƒμ†ν•œ μ—΄κ±°ν˜•μ€ μΆ”κ°€ 상속이 λΆˆκ°€λŠ₯함.) λŒ€μ‹  μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ±°λ‚˜ ν•„λ“œ, λ©”μ„œλ“œ, μƒμ„±μžλ₯Ό κ°€μ§ˆ 수 μžˆμ–΄μ„œ, λ‹¨μˆœν•œ μƒμˆ˜ λͺ¨μŒ μ΄μƒμ˜ κΈ°λŠ₯을 μ œκ³΅ν•¨.

μ»΄νŒŒμΌλŸ¬λŠ” enum을 μ»΄νŒŒμΌν•  λ•Œ λͺ‡ κ°€μ§€ 편의 κΈ°λŠ₯을 μžλ™μœΌλ‘œ μ œκ³΅ν•¨. κ·Έ 쀑 자주 μ“°μ΄λŠ” 것이 values() λ©”μ„œλ“œ μž„. λͺ¨λ“  enum νƒ€μž…μ€ λͺ¨λ“  μƒμˆ˜λ₯Ό 담은 배열을 λ°˜ν™˜ν•˜λŠ” static T[] values() λ©”μ„œλ“œ λ₯Ό κ°€μ§€λ©°, μƒμˆ˜ μ„ μ–Έ μˆœμ„œμ— 따라 배열에 λ‹΄μ•„ 돌렀쀌. 이λ₯Ό 톡해 μ—΄κ±°ν˜•μ˜ λͺ¨λ“  값듀을 순회(iterate) ν•  수 있음. λ˜ν•œ valueOf(String name) λ©”μ„œλ“œλ₯Ό μžλ™ μƒμ„±ν•˜μ—¬, ν•΄λ‹Ή enum νƒ€μž…μ—μ„œ μ£Όμ–΄μ§„ 이름과 μΌμΉ˜ν•˜λŠ” μƒμˆ˜ λ₯Ό λ°˜ν™˜ν•΄μ€Œ. 예λ₯Ό λ“€μ–΄ Day.valueOf("MONDAY") λŠ” Day.MONDAY μƒμˆ˜λ₯Ό 돌렀쀌. μ΄λ•Œ 인자둜 μ „λ‹¬ν•œ λ¬Έμžμ—΄κ³Ό λ™μΌν•œ μ΄λ¦„μ˜ μƒμˆ˜κ°€ μ—†λ‹€λ©΄ IllegalArgumentException 이 λ°œμƒν•¨.

κ·Έ 외에도, 각 enum μƒμˆ˜λŠ” ordinal() λ©”μ„œλ“œ λ₯Ό κ°€μ§€κ³  μžˆλŠ”λ°, μ΄λŠ” ν•΄λ‹Ή μƒμˆ˜κ°€ μ—΄κ±°ν˜• μ„ μ–Έμ—μ„œ μ •μ˜λœ μˆœμ„œ index λ₯Ό μ˜λ―Έν•˜λŠ” μ •μˆ˜λ₯Ό λ°˜ν™˜ν•¨. 예λ₯Ό λ“€μ–΄ Day.SUNDAY.ordinal() 이 0, Day.MONDAY.ordinal() 이 1 을 λ°˜ν™˜ν•˜λŠ” μ‹μž„. ( 첫 μƒμˆ˜μ˜ ordinal 이 0λΆ€ν„° μ‹œμž‘). 이 ordinal 값은 μƒμˆ˜μ˜ μˆœμ„œλ₯Ό λ‚˜νƒ€λ‚΄μ§€λ§Œ, μ—΄κ±°ν˜• μƒμˆ˜μ˜ μˆœμ„œλŠ” 변경될 수 μžˆμœΌλ―€λ‘œ ordinal 값을 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— 직접 μ‚¬μš©ν•˜λŠ” 것은 ꢌμž₯λ˜μ§€ μ•ŠμŒ . λŒ€μ‹  μƒμˆ˜μ˜ κ³ μœ ν•œ μ˜λ―Έκ°€ ν•„μš”ν•˜λ©΄ λ³„λ„μ˜ 값을 ν•„λ“œλ‘œ μ •μ˜ν•˜λŠ” 것이 μ’‹μŒ. λ§ˆμ§€λ§‰μœΌλ‘œ name() λ©”μ„œλ“œλŠ” μƒμˆ˜ μ„ μ–Έλͺ…을 κ·ΈλŒ€λ‘œ λ¬Έμžμ—΄λ‘œ λ°˜ν™˜ν•¨. 이 값은 μ—΄κ±°ν˜• μ„ μ–Έμ—μ„œμ˜ 이름과 μ •ν™•ν•˜κ²Œ μΌμΉ˜ν•˜λ©°, 기본적으둜 toString() λ©”μ„œλ“œλ„ 같은 값을 λ°˜ν™˜ν•˜μ§€λ§Œ ν•„μš”μ— 따라 toString() 을 μ˜€λ²„λΌμ΄λ“œν•˜μ—¬ 좜λ ₯용으둜 λ‹€λ₯Έ λ¬Έμžμ—΄μ„ μ œκ³΅ν•  μˆ˜λ„ 있음.

μ˜ˆμ‹œμ½”λ“œ

κ°„λ‹¨ν•œ 레벨(Level) μ—΄κ±°ν˜•μ„ μ •μ˜ν•˜κ³ , μ œκ³΅λ˜λŠ” λ©”μ„œλ“œλ“€μ„ ν™œμš©ν•œ μ˜ˆμž„.

enum Level { LOW, MEDIUM, HIGH }

for(Level lv : Level.values()) {
    System.out.println(lv + " - ordinal: " + lv.ordinal());
}

Level selected = Level.valueOf("HIGH");
System.out.println("Name: " + selected.name());

μ‹€ν–‰ κ²°κ³Ό 예:

LOW - ordinal: 0
MEDIUM - ordinal: 1
HIGH - ordinal: 2
Name: HIGH

μœ„ μ˜ˆμ—μ„œ Level.values() λ₯Ό 톡해 [LOW, MEDIUM, HIGH] μˆœμ„œμ˜ μƒμˆ˜ λͺ©λ‘μ„ μ–»μ–΄ for-each 둜 μˆœνšŒν–ˆκ³ , 각 μƒμˆ˜μ˜ 이름과 ordinal() 값을 좜λ ₯ν–ˆμŒ. κ·Έ λ‹€μŒ Level.valueOf("HIGH") λ₯Ό μ΄μš©ν•΄ λ¬Έμžμ—΄ "HIGH" 에 λŒ€μ‘λ˜λŠ” μƒμˆ˜λ₯Ό μ–»μ–΄λ‚΄μ–΄, κ·Έ name() 을 좜λ ₯ν–ˆμŒ

  • values() : λͺ¨λ“  μƒμˆ˜ λ₯Ό μ •μ˜ μˆœμ„œλŒ€λ‘œ 담은 배열을 λ°˜ν™˜

  • valueOf(String) : 이름과 μΌμΉ˜ν•˜λŠ” μƒμˆ˜ λ₯Ό λ°˜ν™˜.(λŒ€μ†Œλ¬Έμž μ •ν™•νžˆ μΌμΉ˜ν•΄μ•Ό ν•˜λ©°, μ—†μœΌλ©΄ μ˜ˆμ™Έ)

  • ordinal() : μƒμˆ˜μ˜ μˆœμ„œ 인덱슀 (0λΆ€ν„° μ‹œμž‘) λ₯Ό λ°˜ν™˜.

  • name() : μƒμˆ˜μ˜ 이름 λ¬Έμžμ—΄ 을 λ°˜ν™˜. (주둜 λ””λ²„κΉ…μ΄λ‚˜ μ €μž₯용으둜 μ‚¬μš©, ν•„μš”μ‹œ toString() μ˜€λ²„λΌμ΄λ“œ κ°€λŠ₯)

이 외에도 enum 은 Enum 클래슀의 λ©”μ„œλ“œμΈ compareTo() (μ •μ˜ μˆœμ„œ 비ꡐ)λ‚˜ equals() , hashcode() 등이 κΈ°λ³Έ 제곡되며, switch λ¬Έμ—μ„œλ„ μ—΄κ±°ν˜• μƒμˆ˜λ₯Ό case λ ˆμ΄λΈ”λ‘œ μ‚¬μš©ν•  수 μžˆλŠ” λ“± λ‹€μ–‘ν•œ νŽΈμ˜κ°€ 있음.

2.2 μƒμˆ˜λ³„ λ©”μ„œλ“œ μ˜€λ²„λΌμ΄λ”©( μ „λž΅ νŒ¨ν„΄ μ‘μš©)

Java 의 μ—΄κ±°ν˜•μ€ 각 μƒμˆ˜λ§ˆλ‹€ 각기 λ‹€λ₯Έ λ™μž‘μ„ κ΅¬ν˜„ ν•  수 μžˆλŠ” κ°•λ ₯ν•œ κΈ°λŠ₯을 κ°€μ§€κ³  있음. 사싀 μ—΄κ±°ν˜•μ€ 클래슀이기 λ•Œλ¬Έμ— 내뢀에 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  수 있고, 각 enum μƒμˆ˜λŠ” ν•΄λ‹Ή enum 클래슀의 μΈμŠ€ν„΄μŠ€ μ΄λ―€λ‘œ ν•„μš”ν•œ 경우 μƒμˆ˜λ³„λ‘œ λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œ ν•  수 있음. 이λ₯Ό ν™œμš©ν•˜λ©΄ ν•˜λ‚˜μ˜ enum μƒμˆ˜λ§ˆλ‹€ μ„œλ‘œ λ‹€λ₯Έ 행동 κ·œμΉ™μ„ λΆ€μ—¬ν•  수 μžˆλŠ”λ°, μ΄λŸ¬ν•œ νŒ¨ν„΄μ€ ν”νžˆ μ „λž΅ νŒ¨ν„΄(Strategy Pattern) 을 μ—΄κ±°ν˜•μœΌλ‘œ κ΅¬ν˜„ν•œ 것과 μœ μ‚¬ν•¨.

μƒμˆ˜λ³„λ‘œ λ©”μ„œλ“œλ₯Ό λ‹€λ₯΄κ²Œ κ΅¬ν˜„ν•˜λŠ” λ°©λ²•μœΌλ‘œλŠ” 좔상 λ©”μ„œλ“œ μ„ μ–Έ ν›„ μƒμˆ˜λ³„ κ΅¬ν˜„ 제곡 을 많이 μ‚¬μš©ν•¨. 즉, enum 클래슀 μ•ˆμ— 좔상 λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜κ³ , 각 μƒμˆ˜κ°€ κ·Έ λ©”μ„œλ“œλ₯Ό ꡬ체적으둜 μ˜€λ²„λΌμ΄λ“œ ν•˜λ„λ‘ λ§Œλ“œλŠ” κ²ƒμž„. μ΄λ ‡κ²Œ ν•˜λ©΄ enum μƒμˆ˜λ₯Ό μΆ”κ°€ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œ μƒˆλ‘œμš΄ λ™μž‘μ„ μ‰½κ²Œ ν™•μž₯ν•  수 있고, λ³„λ„μ˜ switch λ¬Έμ΄λ‚˜ λΆ„κΈ° 없이 λ‹€ν˜•μ„±μ„ ν™œμš©ν•  수 있음. μ•„λž˜λŠ” κ°„λ‹¨ν•œ 계산기 연산을 enum 으둜 κ΅¬ν˜„ν•œ μ˜ˆμ‹œμž„. Operation μ—΄κ±°ν˜•μ€ 사칙연산을 λ‚˜νƒ€λ‚΄λŠ” μƒμˆ˜λ“€μ„ κ°€μ§€λ©°, 좔상 λ©”μ„œλ“œ apply λ₯Ό μ„ μ–Έν•˜κ³  각 μƒμˆ˜λ§ˆλ‹€ 이λ₯Ό κ΅¬ν˜„ν•¨.

enum Operation {
    PLUS {
        @Override
        public int apply(int x, int y) { return x + y; }
    },
    MINUS {
        @Override
        public int apply(int x, int y) { return x - y; }
    }
    MULTIPLY {
        @Override
        public int apply(int x, int y) { return x * y; }
    }
    DIVIDE {
        @Override
        public int apply(int x, int y) { return x / y; }
    }
    
    public abstract int apply(int x, int y);
}

// μ‚¬μš© 예
System.out.println(Operation.PLUS,apply(3,4)); // result : 7
System.out.println(Operation.DIVIDE.apply(8,2)); // result : 4

μœ„ μ½”λ“œμ—μ„œ Operation enum 은 apply(int, int) λΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό κ°€μ§€κ³  있고, 각 μƒμˆ˜(PLUS, MINUS, MULTIPLY, DIVIDE) κ°€ μžμ‹ λ§Œμ˜ λ°©μ‹μœΌλ‘œ 이 λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³  있음. Operation.PLUS.apply(3,4) λŠ” λ‚΄λΆ€μ μœΌλ‘œ PLUS μƒμˆ˜μ— κ΅¬ν˜„λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜μ—¬ 3 + 4 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜κ³ , Operation.DIVIDE.apply(8,2) λŠ” DIVIDE μƒμˆ˜μ˜ κ΅¬ν˜„μ„ 싀행함. 이처럼 각 μƒμˆ˜κ°€ 독립적인 λ‘œμ§μ„ κ°€μ§ˆ 수 μžˆμœΌλ―€λ‘œ, μƒˆλ‘œμš΄ 연산을 μΆ”κ°€ν•˜λ €λ©΄ enum 에 μƒμˆ˜λ₯Ό μΆ”κ°€ν•˜κ³  ν•΄λ‹Ή μƒμˆ˜μ— λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜κΈ°λ§Œ ν•˜λ©΄ 됨. λ³„λ„μ˜ 쑰건뢄기 μ½”λ“œ λ³€κ²½ 없이도 ν™•μž₯이 κ°€λŠ₯ν•˜λ©°, μ—΄κ±°ν˜• μžμ²΄κ°€ μ—°μ‚° μ§‘ν•©κ³Ό λ™μž‘μ„ μΊ‘μŠν™”ν•˜λ―€λ‘œ μ½”λ“œκ°€ 깔끔해짐. 이것은 μΌμ’…μ˜ enum 을 μ‚¬μš©ν•œ μ „λž΅ νŒ¨ν„΄ κ΅¬ν˜„μœΌλ‘œ λ³Ό 수 있으며, λŒ€ν‘œμ μΈ ν™œμš© μ‚¬λ‘€μž„. (Java API μ—μ„œλ„ java.math.RoundingMode 의 각 μƒμˆ˜κ°€ round λ©”μ„œλ“œλ₯Ό λ‹€λ₯΄κ²Œ κ΅¬ν˜„ν•˜λŠ” λ“± μœ μ‚¬ν•œ 기법이 ν™œμš©λ˜μ–΄ 있음)

λ§Œμ•½ enum μ—μ„œ 곡톡 λ©”μ„œλ“œλ₯Ό 각 μƒμˆ˜κ°€ μ„œλ‘œ λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λ„λ‘ ν•˜κ³  μ‹Άλ‹€λ©΄ κΌ­ 좔상 λ©”μ„œλ“œκ°€ μ•„λ‹ˆμ–΄λ„ 됨. ν•„μš”ν•œ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•˜κ³ , κΈ°λ³Έ κ΅¬ν˜„μ„ 넣은 λ’€ νŠΉμ • μƒμˆ˜μ—μ„œλ§Œ 이λ₯Ό μ˜€λ²„λΌμ΄λ“œ ν•  μˆ˜λ„ 있음. ν•˜μ§€λ§Œ λŒ€λΆ€λΆ„μ˜ 경우 μœ„μ²˜λŸΌ 좔상 λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜λŠ” νŒ¨ν„΄μ΄ 많이 μ“°μž„. μ΄λŸ¬ν•œ κΈ°λŠ₯ 덕뢄에 μ—΄κ±°ν˜• μƒμˆ˜ 각각이 ν•˜λ‚˜μ˜ 클래슀처럼 λ™μž‘ν•˜λ„λ‘ λ§Œλ“€ 수 있고 , κ΄€λ ¨λœ μƒνƒœλ‚˜ λ©”μ„œλ“œλ₯Ό κ°€μ§ˆ μˆ˜λ„ 있음.

2.3 μ—΄κ±°ν˜•μ˜ μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„

μ—΄κ±°ν˜•μ€ λ‚΄λΆ€μ μœΌλ‘œ Enum 을 ν™•μž₯ν•œ 클래슀 μ΄λ―€λ‘œ, λ‹€λ₯Έ 일반 클래슀처럼 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„(implements) ν•  μˆ˜λ„ 있음. μ—΄κ±°ν˜•μ΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ©΄, κ·Έ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ—΄κ±°ν˜• μƒμˆ˜λ₯Ό λ‹€λ£° 수 μžˆμ–΄ λ‹€ν˜•μ„±μ΄ μ¦κ°€ν•˜κ³ , μ—΄κ±°ν˜• μƒμˆ˜λ“€μ—κ²Œ νŠΉμ • ν–‰μœ„λ₯Ό κ°•μ œν•  수 μžˆλ‹€λŠ” μž₯점이 있음. μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” enum 은 ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ”λ°, 이 κ΅¬ν˜„μ„ 각 μƒμˆ˜λ³„λ‘œ λ‹€λ₯΄κ²Œ ν•  μˆ˜λ„ 있고, κ³΅ν†΅λ˜κ²Œ ν•  μˆ˜λ„ 있음. μƒμˆ˜λ³„λ‘œ λ‹€λ₯΄κ²Œ ν•˜λ €λ©΄ μ•žμ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ enum 내에 좔상 λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜κ±°λ‚˜ μΈν„°νŽ˜μ΄μŠ€μ˜ λ©”μ„œλ“œλ₯Ό 좔상 λ©”μ„œλ“œν™”ν•˜μ—¬ 각 μƒμˆ˜κ°€ μ˜€λ²„λΌμ΄λ“œν•˜κ²Œ λ§Œλ“€λ©΄ 됨.

예λ₯Ό λ“€μ–΄, κ°„λ‹¨ν•œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό enum 으둜 κ΅¬ν˜„ν•΄λ΄„. λ‹€μŒ μ½”λ“œλŠ” Greeting μ΄λΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€κ³ , GreetingType μ—΄κ±°ν˜•μ΄ 이λ₯Ό κ΅¬ν˜„ν•œ μ‚¬λ‘€μž„. 각 μƒμˆ˜λŠ” greet() λ©”μ„œλ“œλ₯Ό 자기만의 λ°©μ‹μœΌλ‘œ μ˜€λ²„λΌμ΄λ“œν•˜κ³  있음.

interface Greeting {
    void greet();
}

enum GreetingType implements Greeting {
    HELLO {
        @Override
        public void greet() {
            System.out.println("Hello!");
        }
    },
    GOODBYE {
        @Override
        public void greet() {
            System.out.println("Goodbye!");
        }
    }
}

// μ‚¬μš© 예
Greeting hello = GreetingType.HELLO;
hello.greet();        // result : Hello
GreetingType.GOODBYE.greet(); // result Goodbye!

μœ„μ—μ„œ GreetingType μ—΄κ±°ν˜•μ€ Greeting μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν–ˆμœΌλ―€λ‘œ, GreetingType 의 λͺ¨λ“  μƒμˆ˜λŠ” Greeting νƒ€μž…μœΌλ‘œ 취급될 수 있음. HELLO 와 GOODBYE μƒμˆ˜ 각각이 greet() λ©”μ„œλ“œμ˜ κ΅¬ν˜„μ„ μ œκ³΅ν•˜μ—¬, 호좜 μ‹œ μ„œλ‘œ λ‹€λ₯Έ λ©”μ‹œμ§€λ₯Ό 좜λ ₯함. 이처럼 μ—΄κ±°ν˜•μ΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ©΄ 각 μƒμˆ˜λ₯Ό μΈν„°νŽ˜μ΄μŠ€μ˜ κ΅¬ν˜„μ²΄λ‘œ ν™œμš© ν•  수 있음. 예λ₯Ό λ“€μ–΄ 인자둜 Greeting νƒ€μž…μ„ λ°›λŠ” λ©”μ„œλ“œμ— GreetingType.HELLO λ₯Ό 전달할 수 있고, μ΄λŠ” λ‹€ν˜•μ μœΌλ‘œ λ™μž‘ν•¨.

μ—΄κ±°ν˜•μ€ μ—¬λŸ¬ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  μˆ˜λ„ 있음. 참고둜, Java 의 λͺ¨λ“  enum 은 컴파일 μ‹œ μžλ™μœΌλ‘œ java.lang.Enum 을 μƒμ†ν•˜κ³  java.lang.Comparable κ³Ό java.io.Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ λ˜μ–΄ 있음. λ”°λΌμ„œ enum κ°„ λΉ„κ΅λ‚˜ 직렬화 등이 기본적으둜 κ°€λŠ₯ν•˜λ©°, μΆ”κ°€λ‘œ κ°œλ°œμžκ°€ μ›ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ—¬ κΈ°λŠ₯을 ν™•μž₯ν•  수 있음. μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 enum μƒμˆ˜μ˜ 행동을 μΆ”μƒν™”ν•˜λ©΄, enum 을 μ‚¬μš©ν•˜λŠ” μ½”λ“œ μž…μž₯μ—μ„œ κ΅¬ν˜„μ„ λͺ°λΌλ„ ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μΌκ΄€λœ λ™μž‘μ„ μ΄λŒμ–΄λ‚Ό 수 μžˆλ‹€λŠ” 이점도 있음.

2.4 EnumSet κ³Ό EnumMap

Java Collections Framework λŠ” μ—΄κ±°ν˜•κ³Ό ν•¨κ»˜ 쓰기에 μ΅œμ ν™”λœ μ»¬λ ‰μ…˜ κ΅¬ν˜„μ²΄λ‘œ EnumSet κ³Ό EnumMap 클래슀λ₯Ό μ œκ³΅ν•¨. 이듀은 λ‚΄λΆ€ κ΅¬ν˜„μ„ μ—΄κ±°ν˜•μ— νŠΉν™”ν•˜μ—¬, μ—΄κ±°ν˜• μƒμˆ˜λ₯Ό λ‹€λ£° λ•Œ μ„±λŠ₯κ³Ό λ©”λͺ¨λ¦¬ νš¨μœ¨μ„ 높일 수 μžˆλŠ” μžλ£Œκ΅¬μ‘°μž„. μ—΄κ±°ν˜• νƒ€μž… μ „μš© μ΄λΌλŠ” μ œμ•½μ΄ μžˆμ§€λ§Œ, 그만큼 일반적인 Set μ΄λ‚˜ Map κ΅¬ν˜„λ³΄λ‹€ λ›°μ–΄λ‚œ μ΅œμ ν™”κ°€ 이루어져 있음.

  • EnumSet :

    EnumSet<E extends Enum<E>> 은 νŠΉμ • μ—΄κ±°ν˜• νƒ€μž…μ˜ κ°’λ§Œ 담을 수 μžˆλŠ” μ§‘ν•©(Set) κ΅¬ν˜„μ²΄μž„. λͺ¨λ“  μ›μ†Œκ°€ λ™μΌν•œ enum νƒ€μž…μ΄μ–΄μ•Ό ν•˜λ©°, λ‚΄λΆ€μ μœΌλ‘œ λΉ„νŠΈ 벑터(bit vector) 둜 μ›μ†Œλ“€μ„ 관리함. 각 μ—΄κ±°ν˜• μƒμˆ˜μ— ν•˜λ‚˜μ˜ λΉ„νŠΈκ°€ λŒ€μ‘λ˜λ©°, μƒμˆ˜κ°€ EnumSet 에 ν¬ν•¨λ˜λ©΄ κ·Έ λΉ„νŠΈκ°€ 1둜 μ„€μ •λ˜λŠ” μ‹μ˜ 맀우 μ»΄νŒ©νŠΈν•œ ν‘œν˜„μ„ μ‚¬μš©ν•¨. μ΄λŸ¬ν•œ ꡬ쑰 덕뢄에 λ©”λͺ¨λ¦¬ 곡간 을 효율적으둜 μ“°κ³  μ—°μ‚° 속도도 맀우 빠름 . λΉ„νŠΈ μ—°μ‚°μœΌλ‘œ κ΅¬ν˜„λ˜μ–΄ μžˆμœΌλ―€λ‘œ ν•©μ§‘ν•©, ꡐ집합 λ“±μ˜ μ§‘ν•© 연산도 λΉ λ₯΄κ²Œ μˆ˜ν–‰λ˜λ©°, μ›μ†Œμ˜ 쑴재 μ—¬λΆ€ 체크, μΆ”κ°€/μ‚­μ œ 등이 μƒμˆ˜ μ‹œκ°„ O(1) 에 κ°€λŠ₯함. EnumSet 은 전톡적인 μ •μˆ˜ λΉ„νŠΈ 마슀크λ₯Ό λŒ€μ²΄ν•˜λŠ” νƒ€μž… μ•ˆμ „ν•œ λŒ€μ•ˆ 으둜 ꢌμž₯되며, μ—΄κ±°ν˜• μƒμˆ˜λ“€μ„ μ§‘ν•©μœΌλ‘œ 닀루어야 ν•  λ•Œ μ΅œμƒμ˜ μ„±λŠ₯을 μ œκ³΅ν•¨. EnumSet 을 생성할 λ•ŒλŠ” 일반적으둜 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•¨. 예λ₯Ό λ“€μ–΄ EnumSet.of(A, B) λŠ” μ£Όμ–΄μ§„ μƒμˆ˜λ“€λ‘œ κ΅¬μ„±λœ EnumSet을 λ§Œλ“€κ³ , EnumSEt.allOf(EnumType.class) λŠ” ν•΄λ‹Ή μ—΄κ±°ν˜•μ˜ λͺ¨λ“  μƒμˆ˜λ₯Ό ν¬ν•¨ν•˜λŠ” EnumSet 을 λ§Œλ“¬. EnumSet.noneOf(EnumType.class) λŠ” λΉ„μ–΄μžˆλŠ” EnumSet 을 생성함. λ‹€μŒμ€ EnumSet μ‚¬μš© μ˜ˆμ‹œμž„.

enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

EnumSet<Day> weekend = EnumSet.of(Day.SAT, DAY.SUN);
System.out.println(weekend);        // result : [SAT, SUN]

EnumSet<Day> workdays = EnumSet.complementOf(weekend);
System.out.println(workdays);       // result : [MON, TUE, WED, THU, FRI]

μœ„ μ½”λ“œμ—μ„œ EnumSet.of(Day.SAT, Day.SUN) 은 SAT 와 SUN 만 담은 EnumSet 을 μƒμ„±ν•˜κ³  complementOf λ©”μ„œλ“œλŠ” μ£Όμ–΄μ§„ EnumSet 에 ν¬ν•¨λ˜μ§€ μ•ŠλŠ” μ—΄κ±°ν˜• κ°’λ“€λ‘œ κ΅¬μ„±λœ μƒˆλ‘œμš΄ EnumSet 을 λ°˜ν™˜ν•¨. λ”°λΌμ„œ workdays λŠ” 주말을 μ œμ™Έν•œ μš”μΌλ“€λ‘œ μ±„μ›Œμ§. EnumSet 은 λ‚΄λΆ€μ μœΌλ‘œ λΉ„νŠΈ 연산을 ν™œμš©ν•˜λ―€λ‘œ, μ›μ†Œ κ°œμˆ˜κ°€ λ§Žμ•„λ„ λΉ λ₯΄κ²Œ λ™μž‘ν•˜λ©°, HashSet λŒ€λΉ„ μ„±λŠ₯상 이점 이 큼. 단, EnumSet 은 enum νƒ€μž…λ‹Ή ν•˜λ‚˜μ˜ λΉ„νŠΈμ…‹μœΌλ‘œ ν‘œν˜„λ˜λ―€λ‘œ λ™μ‹œμ— μ—¬λŸ¬ enum νƒ€μž…μ„ ν˜Όν•©ν•˜μ—¬ μ €μž₯ν•  수 μ—†μœΌλ©°, null 값도 ν—ˆμš©λ˜μ§€ μ•ŠμŒ. (null 을 λ„£μœΌλ €κ³  ν•˜λ©΄ NullPointerException λ°œμƒ). λŒ€λΆ€λΆ„μ˜ 경우 μ΄λŸ¬ν•œ μ œν•œμ€ λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμœΌλ©°, μ—΄κ±°ν˜• μƒμˆ˜μ˜ 집합을 λ‹€λ£° λ•Œ EnumSet 을 μ‚¬μš©ν•˜λŠ” 것이 ꢌμž₯됨.

  • EnumMap :

    EnumMap<K extends Enum<K, V> λŠ” μ—΄κ±°ν˜•μ„ ν‚€λ‘œ μ‚¬μš©ν•˜λŠ” μ „μš© Map κ΅¬ν˜„μ²΄ μž„. EnumMap의 ν‚€λŠ” λͺ¨λ‘ 같은 enum νƒ€μž…μ΄μ–΄μ•Ό ν•˜λ©°, λ‚΄λΆ€μ μœΌλ‘œ λ°°μ—΄ 을 μ΄μš©ν•΄ κ΅¬ν˜„λ˜μ–΄ 있음. μ—΄κ±°ν˜• μƒμˆ˜μ˜ ordinal() 값을 λ°°μ—΄ index 둜 μ‚¬μš©ν•˜μ—¬ λŒ€μ‘λ˜λŠ” 값을 μ €μž₯ν•˜λ―€λ‘œ, ν•΄μ‹±(Hashing) 을 μ‚¬μš©ν•˜μ§€ μ•Šκ³ λ„ 맀우 λΉ λ₯Έ 쑰회/κ°±μ‹  μ„±λŠ₯ 을 λ³΄μž„. κΈ°λ³Έμ—°μ‚°(쑰회, μΆ”κ°€, μ‚­μ œ λ“±) 이 μƒμˆ˜ μ‹œκ°„ 에 μ‹€ν–‰λ˜λ©°, 일반적인 HashMap 보닀도 νš¨μœ¨μ μž„. λ˜ν•œ λ°°μ—΄ 기반 κ΅¬ν˜„ 덕뢄에 λ©”λͺ¨λ¦¬λ„ μ—΄κ±°ν˜• μš”μ†Œ κ°œμˆ˜μ— λ”± 맞좰 μ‚¬μš©ν•  수 μžˆμ–΄ λ‚­λΉ„κ°€ 적고 λ©”λͺ¨λ¦¬ μ‚¬μš©μ΄ 컴팩트 함. EnumMap 을 생성할 λŒ€λŠ” ν‚€λ‘œ μ‚¬μš©ν•  enum 의 Class 객체가 ν•„μš”ν•¨. 예λ₯Ό λ“€μ–΄ new EnumMap<>(Day.class) 처럼 enum νƒ€μž…μ„ μ§€μ •ν•˜λ©΄ ν•΄λ‹Ή enum 의 λͺ¨λ“  값을 담을 수 μžˆλŠ” λ‚΄λΆ€ 배열이 섀정됨.(μ΄ˆκΈ°μ—λŠ” 값이 λΉ„μ–΄μžˆκ³ , ν•„μš”ν•œ 킀에 λŒ€ν•΄μ„œλ§Œ 값이 μ±„μ›Œμ§.) EnumMap 은 iterator(순회) μ‹œ μ—΄κ±°ν˜• μ •μ˜ μˆœμ„œ(μžμ—°μˆœμ„œ) λ₯Ό μœ μ§€ν•˜λŠ” 것도 νŠΉμ§•μž„. μ΄λŠ” HashMap 이 ν•΄μ‹œκ°’ μˆœμ„œλ‘œ ν‚€λ₯Ό λ°°μΉ˜ν•˜λŠ” 것과 달리, EnumMap 은 μ—΄κ±°ν˜• μƒμˆ˜μ˜ μˆœμ„œλ₯Ό λ”°λ₯΄λ―€λ‘œ 예츑 κ°€λŠ₯ν•œ μˆœμ„œλ₯Ό λ³΄μž„. λ‹€μŒμ€ EnumMap μ‚¬μš© μ˜ˆμ‹œμž„.

EnumMap<Day, String> dayType = new EnumMap<>(Day.class);
dayType.put(Day.MON, "Weekday");
dayType.put(Day.SAT, "Weekend");

System.out.println(dayType.get(Day.MON));        // result : Weekday
System.out.println(dayType);                     // result {MON=Weekday, SAT=Weekend}

μœ„ μ½”λ“œμ—μ„œ dayType 은 Day μ—΄κ±°ν˜•μ„ ν‚€λ‘œ ν•˜κ³  λ¬Έμžμ—΄μ„ κ°’μœΌλ‘œ κ°€μ§€λŠ” EnumType μž„. Day.MON 킀에 "Weekday" λ₯Ό λ„£κ³ , Day.SAT 킀에 "Weekend" λ₯Ό 넣은 ν›„ μ‘°νšŒμ™€ 좜λ ₯ 예λ₯Ό λ³΄μ—¬μ€Œ. 좜λ ₯ κ²°κ³Όλ₯Ό 보면 {MON=Weekday, SAT=Weekend} 와 같이 ν‚€μ˜ μ„ μ–Έ μˆœμ„œ(μ›”μš”μΌμ΄ ν† μš”μΌλ³΄λ‹€ μ•žμ„  μˆœμ„œ) κ°€ μœ μ§€λ˜μ–΄ λ‚˜νƒ€λ‚¨.

EnumMap 은 λͺ¨λ“  ν‚€λ₯Ό λ°°μ—΄λ‘œ 직접 μ ‘κ·Ό ν•˜λ―€λ‘œ 맀우 λΉ λ₯΄λ©°, ν‚€μ˜ 전체 κ°―μˆ˜κ°€ μ—΄κ±°ν˜• μƒμˆ˜μ˜ 수둜 ν•œμ •λ˜κΈ° λ•Œλ¬Έμ— HashMap 처럼 μš©λŸ‰μ΄ λ™μ μœΌλ‘œ λŠ˜μ–΄λ‚˜λŠ” 과정도 μ—†μŒ. λ”°λΌμ„œ μ—΄κ±°ν˜•μ„ ν‚€λ‘œ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” μƒν™©μ—μ„œλŠ” 항상 EnumMap 을 μš°μ„ μ μœΌλ‘œ κ³ λ € ν•˜λŠ” 것이 μ’‹μŒ. 예λ₯Ό λ“€μ–΄ μ—΄κ±°ν˜• μƒμˆ˜λ₯Ό μ–΄λ–€ 값에 λ§€ν•‘ν•˜λŠ” 경우 (switch 문으둜일일이 λΆ„κΈ°ν•˜λŠ” λŒ€μ‹ ) EnumMap 에 μƒμˆ˜-κ°’ μŒμ„ λ„£μ–΄ κ΄€λ¦¬ν•˜λ©΄ μ½”λ“œκ°€ 깔끔해지고 μ„±λŠ₯도 μš°μˆ˜ν•¨. EnumMap 도 EnumSet κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ null ν‚€λ₯Ό μ‚¬μš©ν•  수 μ—†μ§€λ§Œ null 값은 ν—ˆμš©ν•¨. 그리고 thread-safe ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μ—¬λŸ¬ μ“°λ ˆλ“œμ—μ„œ λ™μ‹œ μˆ˜μ •μ΄ ν•„μš”ν•˜λ©΄ λ³„λ„λ‘œ λ™κΈ°ν™”ν•˜κ±°λ‚˜ Collections.synchronizedMap 으둜 감싸야함.

Last updated

Was this helpful?