Skip to content

Latest commit

Β 

History

History
502 lines (344 loc) Β· 28.6 KB

File metadata and controls

502 lines (344 loc) Β· 28.6 KB

item 33 : νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλ₯Ό κ³ λ €ν•˜λΌ

1. νƒ€μž… μ•ˆμ „μ΄μ€‘ μ»¨ν…Œμ΄λ„ˆ 방식 κ°œλ… 및 μ‚¬μš© 방법

1) νƒ€μž…μ•ˆμ „μ΄μ€‘ μ»¨ν…Œμ΄λ„ˆ λ°©μ‹μ΄λž€?

기쑴의 μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆ(Set<E>, Map<K, V> λ“±)μ—μ„œλŠ” μ§€μ •λœ 개수의 νƒ€μž… λ§€κ°œλ³€μˆ˜λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.
예λ₯Ό λ“€μ–΄, Set<E>μ—λŠ” μ›μ†Œμ˜ νƒ€μž…μ„ λœ»ν•˜λŠ” 단 ν•˜λ‚˜μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜λ§Œ 있으면 되며, Map<K,V> μ—λŠ” 킀와 값을 λœ»ν•˜λŠ” 2개만 ν•„μš”ν•˜λ‹€.

{% hint style="warning" %} ν•˜μ§€λ§Œ μ»¨ν…Œμ΄λ„ˆ μžμ²΄κ°€ μ•„λ‹Œ "ν‚€"λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•œ λ‹€μŒ, μ»¨ν…Œμ΄λ„ˆμ— 값을 λ„£κ±°λ‚˜ λΊ„ λ•Œ λ§€κ°œλ³€μˆ˜ν™”ν•œ ν‚€λ₯Ό ν•¨κ»˜ μ œκ³΅ν•œλ‹€λ©΄ 더 μœ μ—°ν•˜κ²Œ μ—¬λŸ¬ νƒ€μž…μ„ 받을 수 μžˆμ§€ μ•Šμ„κΉŒ? {% endhint %}

λ°”λ‘œ μ΄λŸ¬ν•œ 섀계 방식을, μš°λ¦¬λŠ” νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ νŒ¨ν„΄μ΄λΌκ³  ν•œλ‹€.

public class Favorites {
    public <T> void putFavorite(Class<T> type, T instance); // ν‚€κ°€ λ§€κ°œλ³€μˆ˜ν™” 됨
    public <T> T getFavorite(Class<T> type); 
}

μ»¨ν…Œμ΄λ„ˆλ₯Ό νƒ€μž…λ³„λ‘œ λ‚˜λˆ„μ§€ μ•Šκ³ , ν‚€ μžμ²΄μ— νƒ€μž…μ„ λ§€κ°œλ³€μˆ˜ν™”ν•˜λŠ” 방식을 μ œμ•ˆν•˜κ³  μžˆλ‹€. 즉, νŠΉμ • 킀에 μ›ν•˜λŠ” νƒ€μž…μ„ μ§€μ •ν•˜κ³ , 값을 μ €μž₯ν•˜κ±°λ‚˜ μ‘°νšŒν•  λ•Œ 이 킀와 ν•¨κ»˜ νƒ€μž… 정보λ₯Ό μ œκ³΅ν•˜μ—¬ 더 μœ μ—°ν•˜κ²Œ μ—¬λŸ¬ νƒ€μž…μ˜ 값을 μ €μž₯ν•˜κ³  관리할 수 μžˆλŠ” ꡬ쑰λ₯Ό μƒκ°ν•˜λŠ” 것이닀.

{% hint style="info" %} 예제λ₯Ό 보기 μ „, μ—¬κΈ°μ„œ μ œλ„€λ¦­μ€ Set, Map<K,V> λ“±μ˜ μ»¬λ ‰μ…˜κ³Ό Threadl_ocal, AtomicReference λ“±μ˜ λ‹¨μΌμ›μ†Œ μ»¨ν…Œμ΄λ„ˆμ—λ„ ν”νžˆ 쓰인닀. 이런 λͺ¨λ“  μ“°μž„μ—μ„œ λ§€κ°œλ³€μˆ˜ν™”λ˜λŠ” λŒ€μƒμ€ (μ›μ†Œκ°€ μ•„λ‹Œ) μ»¨ν…Œμ΄λ„ˆ μžμ‹ μ΄λ‹€. {% endhint %}

μ—¬κΈ°μ„œ "λ§€κ°œλ³€μˆ˜ν™”λ˜λŠ” λŒ€μƒμ΄ μ»¨ν…Œμ΄λ„ˆ μžμ‹ "μ΄λΌλŠ” 것은, μ œλ„€λ¦­ νƒ€μž…μ΄ μ μš©λ˜λŠ” λ²”μœ„κ°€ μ»¨ν…Œμ΄λ„ˆ νƒ€μž…μ΄λΌλŠ” μ˜λ―Έμ΄λ‹€. 즉, Set<E>, Map<K, V>, ThreadLocal<T>, AtomicReference<T> λ“±μ—μ„œ μ œλ„€λ¦­ νƒ€μž…μ€ ν•΄λ‹Ή μ»¨ν…Œμ΄λ„ˆμ˜ ꡬ쑰 자체λ₯Ό νƒ€μž…μœΌλ‘œ λ§€κ°œλ³€μˆ˜ν™”ν•˜κ³  μžˆλ‹€λŠ” λœ»μ΄λ‹€.

μ›μ†Œ(Element)와 μ»¨ν…Œμ΄λ„ˆ(Container) ꡬ뢄

  • μ›μ†Œ (Element): μ»¨ν…Œμ΄λ„ˆ μ•ˆμ— μ €μž₯λ˜λŠ” μ‹€μ œ 데이터, 예λ₯Ό λ“€μ–΄ Set<Integer>μ—μ„œ μ›μ†ŒλŠ” Integer νƒ€μž…μ˜ 데이터듀이 λœλ‹€.
  • μ»¨ν…Œμ΄λ„ˆ(Container): μ›μ†Œλ“€μ„ λ‹΄λŠ” κ·Έλ¦‡μœΌλ‘œ, μ›μ†Œλ“€μ΄ λ‹΄κΈ°λŠ” ꡬ쑰 μžμ²΄κ°€ μ»¨ν…Œμ΄λ„ˆμ΄λ‹€. 예λ₯Ό λ“€μ–΄ Set<Integer>μ—μ„œ Set이 μ»¨ν…Œμ΄λ„ˆμ— ν•΄λ‹Ήν•œλ‹€.

λ§€κ°œλ³€μˆ˜ν™”λœ λŒ€μƒμ΄ "μ»¨ν…Œμ΄λ„ˆ"λΌλŠ” 의미

Set<E> 같은 μ œλ„€λ¦­ μ»¬λ ‰μ…˜μ„ 예둜 듀어보면, Set<Integer>, Set<String>κ³Ό 같이 νŠΉμ • νƒ€μž…μ˜ μ›μ†Œλ“€μ„ λ‹΄λŠ” ꡬ쑰둜 λ§€κ°œλ³€μˆ˜ν™”λ  뿐, μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜ Eκ°€ "μ›μ†Œ"λ₯Ό 직접 λ§€κ°œλ³€μˆ˜ν™”ν•˜λŠ” 것이 μ•„λ‹ˆλ‹€.

즉, μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ μ •μ˜λœ 것은 μ›μ†Œμ˜ νƒ€μž…μ΄ μ•„λ‹Œ "μ»¨ν…Œμ΄λ„ˆ"κ°€ μ›μ†Œλ₯Ό μ–΄λ–€ νƒ€μž…μœΌλ‘œ κ΄€λ¦¬ν•˜λŠ”κ°€λ₯Ό κ²°μ •ν•˜λŠ” 것이닀.

μ˜ˆμ‹œ 1: Set<E>

Set<String> stringSet = new HashSet<>();
Set<Integer> intSet = new HashSet<>();
  • Set<String>κ³Ό Set<Integer>λŠ” λ‘˜ λ‹€ "Set"μ΄λΌλŠ” λ™μΌν•œ μ»¨ν…Œμ΄λ„ˆμ΄λ‹€.
  • λ‹€λ§Œ, μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜ Eλ₯Ό 톡해 μ»¨ν…Œμ΄λ„ˆκ°€ μ–΄λ–€ νƒ€μž…μ˜ μ›μ†Œ(String λ˜λŠ” Integer)λ₯Ό κ°€μ§ˆμ§€ μ •μ˜ν•œλ‹€.

μ˜ˆμ‹œ 2: AtomicReference<T>

AtomicReference<String> atomicString = new AtomicReference<>("hello");
AtomicReference<Integer> atomicInt = new AtomicReference<>(123);
  • AtomicReferenceλŠ” 단일 μ›μ†Œλ₯Ό λ‹΄λŠ” μ»¨ν…Œμ΄λ„ˆμ΄λ©°, μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜ TλŠ” λ‹΄κΈΈ μ›μ†Œμ˜ νƒ€μž…μ„ μ§€μ •ν•  뿐, μ›μ†Œ 자체λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.
  • 즉, μ»¨ν…Œμ΄λ„ˆ(μ—¬κΈ°μ„œλŠ” AtomicReference)κ°€ String λ˜λŠ” Integer νƒ€μž…μ˜ μ›μ†Œλ₯Ό λ‹΄λŠ” 방식을 λ§€κ°œλ³€μˆ˜ν™”ν•˜λŠ” 것이닀.
// Set μ˜ˆμ‹œ: μ—¬λŸ¬ μ›μ†Œλ₯Ό 관리
Set<String> stringSet = new HashSet<>();
stringSet.add("hello");
stringSet.add("world");

// AtomicReference μ˜ˆμ‹œ: 단일 μ›μ†Œλ₯Ό μ›μžμ μœΌλ‘œ 관리
AtomicReference<String> atomicString = new AtomicReference<>("hello");
atomicString.set("world");

λ”°λΌμ„œ μ œλ„€λ¦­ λ§€κ°œλ³€μˆ˜λŠ” 항상 "μ»¨ν…Œμ΄λ„ˆκ°€ μ›μ†Œλ₯Ό μ–΄λ–€ νƒ€μž…μœΌλ‘œ μ·¨κΈ‰ν•˜λŠ”μ§€"λ₯Ό κ²°μ •ν•˜λ©°, μ›μ†Œκ°€ 직접 λ§€κ°œλ³€μˆ˜ν™”λ˜λŠ” 것이 μ•„λ‹ˆλΌ, μ»¨ν…Œμ΄λ„ˆκ°€ μ›μ†Œμ˜ νƒ€μž…μ— 따라 ꡬ쑰λ₯Ό κ΄€λ¦¬ν•˜λŠ” 방식을 μ •μ˜ν•˜λŠ” 것이닀. γ„·

λ‹€μŒκ³Ό 같은 κ΅¬μ‘°μ—μ„œ, Key 객체 μžμ²΄κ°€ νŠΉμ • νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ •μ˜λ˜λ©°, 이 킀와 ν•¨κ»˜ μ»¨ν…Œμ΄λ„ˆμ—μ„œ 값을 λ„£κ³  λΉΌλŠ” λ°©μ‹μ˜ μ˜ˆμ œμ΄λ‹€.

// Key ν΄λž˜μŠ€μ— νƒ€μž… λ§€κ°œλ³€μˆ˜ μ •μ˜
public class Key<T> {
    // νƒ€μž… μ•ˆμ „ν•œ ν‚€ 클래슀
}

// μ»¨ν…Œμ΄λ„ˆ 클래슀
public class Container {
    private final Map<Key<?>, Object> values = new HashMap<>();

    // 값을 μ €μž₯ν•  λ•Œ νƒ€μž…μ— λ§žλŠ” ν‚€λ₯Ό μ‚¬μš©
    public <T> void put(Key<T> key, T value) {
        values.put(key, value);
    }

    // 값을 μ‘°νšŒν•  λ•Œ νƒ€μž…μ— λ§žλŠ” ν‚€λ₯Ό μ‚¬μš©ν•˜μ—¬ νƒ€μž… μ•ˆμ „μ„± 보μž₯
    public <T> T get(Key<T> key) {
        return (T) values.get(key);
    }
}

이 λ°©μ‹μ˜ 핡심은, μ»¨ν…Œμ΄λ„ˆκ°€ μ•„λ‹Œ ν‚€ 객체에 νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό λΆ€μ—¬ν•˜μ—¬, μ—¬λŸ¬ νƒ€μž…μ˜ 값을 ν•˜λ‚˜μ˜ μ»¨ν…Œμ΄λ„ˆμ— νƒ€μž… μ•ˆμ „ν•˜κ²Œ λ‹΄κ³  관리할 수 μžˆλ‹€λŠ” 점이닀.

μ»¨ν…Œμ΄λ„ˆλ₯Ό 클래슀둜 μ΄ν•΄ν•˜λ©΄ μ•ŒκΈ° νŽΈν•˜λ‹€

2) νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ κ°œλ…

사싀 class 의 νƒ€μž…μ΄ Class<T> μ œλ„€λ¦­μ΄κΈ° λ•Œλ¬Έμ—, 각 νƒ€μž…μ˜ Class 객체λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•œ ν‚€ μ—­ν• λ‘œ μ‚¬μš©ν•˜λŠ” 것이 κ°€λŠ₯ν•΄μ§„λ‹€. ex) String.class νƒ€μž…μ€ Class<String>, Integer.class의 νƒ€μž…μ€ Class<Integer>

ν•œνŽΈ, μ»΄νŒŒμΌνƒ€μž„ νƒ€μž… 정보와 λŸ°νƒ€μž„ νƒ€μž… 정보λ₯Ό μ•Œμ•„λ‚΄κΈ° μœ„ν•΄ λ©”μ„œλ“œλ“€μ΄ μ£Όκ³ λ°›λŠ” class 리터 λŸ΄μ„ νƒ€μž… 토큰(type token)이라 ν•œλ‹€.

{% hint style="success" %} κ°€μž₯ μ€‘μš”ν•œ 것은, μš°λ¦¬λŠ” 이λ₯Ό 톡해 μ œλ„€λ¦­μ—μ„œμ˜ μ»΄νŒŒμΌνƒ€μž„ νƒ€μž… μ•ˆμ „μ„±μ΄ μ•„λ‹Œ λŸ°νƒ€μž„ νƒ€μž… μ•ˆμ „μ„±μ„ 얻을 수 μžˆλ‹€λŠ” 것이닀. {% endhint %}

3) νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ κ΅¬ν˜„

public class Favorites{
    private Map<Class<?>, Object> favorites = new HashMap<>();

    public <T> void putFavorite(Class<T> type, T instance) {
        favorites.put(Objects.requireNonNull(type), instance);
    }

    public <T> T getFavorite(Class<T> type) {
        return type.cast(favorites.get(type));
    }
}
  1. Map<Class<?>, Object>
    ν‚€λ₯Ό λΉ„ν•œμ •μ μΈ μ™€μΌλ“œμΉ΄λ“œ νƒ€μž…μœΌλ‘œ μ„ μ–Έν•˜μ˜€κΈ° λ•Œλ¬Έμ—, 이λ₯Ό ν†΅ν•΄μ„œ λ‹€μ–‘ν•œ λ§€κ°œλ³€μˆ˜ν™” νƒ€μž…μ˜ ν‚€λ₯Ό ν—ˆμš©ν•  수 있게 λ˜μ—ˆλ‹€. λ§Œμ•½ Map<Class<T>, Object> μ˜€λ‹€λ©΄ 였직 ν•œκ°€μ§€ νƒ€μž…μ˜ ν‚€λ§Œ 담을 수 μžˆμ—ˆμ„ 것이닀.
  2. Class.cast
    value κ°€ Object νƒ€μž…μ΄λ―€λ‘œ 맡에 λ„£μ„λ•Œ 값이 ν‚€ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λΌλŠ” 것이 보μž₯λ˜μ§€ μ•ŠλŠ”λ‹€. λ”°λΌμ„œ λ§΅μ—μ„œ κ°€μ Έμ˜¬λ•ŒλŠ” cast λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ 이 객체 μ°Έμ‘°λ₯Ό class 객체가 κ°€λ¦¬ν‚€λŠ” T νƒ€μž…μœΌλ‘œ 동적 λ³€ν™˜ν•˜κ³  μžˆλ‹€.

그런데 cast λ©”μ„œλ“œκ°€ 단지 인수λ₯Ό κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•˜κΈ°λ§Œ ν•œλ‹€λ©΄ ꡳ이 μ™œ μ‚¬μš© ν•˜λŠ” κ²ƒμΌκΉŒ?

κ·Έ μ΄μœ λŠ” cast λ©”μ„œλ“œμ˜ μ‹œκ·Έλ‹ˆμ²˜κ°€ Class ν΄λž˜μŠ€κ°€ μ œλ„€λ¦­μ΄λΌλŠ” 이점을 μ™„λ²½νžˆ ν™œμš©ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. λ‹€μŒ μ½”λ“œμ—μ„œ 보듯 cast의 λ°˜ν™˜ νƒ€μž…μ€ Class 객체의 νƒ€μž… λ§€κ°œλ³€μˆ˜μ™€ κ°™λ‹€.

πŸ”– cast λ©”μ„œλ“œ
ν˜•λ³€ν™˜ μ—°μ‚°μžμ˜ 동적 λ²„μ „μœΌλ‘œ, μ£Όμ–΄μ§„ μΈμˆ˜κ°€ Class 객체가 μ•Œλ €μ£ΌλŠ” νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€μΈμ§€ κ²€μ‚¬ν•œ λ‹€μŒ, λ§žλ‹€λ©΄ λ°˜ν™˜ν•˜κ³  μ•„λ‹ˆλ©΄ ClassCastException 을 λ˜μ§„λ‹€. 이λ₯Ό ν™œμš©ν•˜λ©΄, T 둜 비검사 ν˜•λ³€ν™˜μ„ ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. νƒ€μž…μ„ λ”μš± μ•ˆμ „ν•˜κ²Œ λ§Œλ“€μ–΄μ€€λ‹€.

public class Class<T>{
	T cast(Object obj);
}

{% hint style="info" %} 쒀더, μžμ„Ένžˆ value κ°€ Object νƒ€μž…μ΄λ―€λ‘œ 맡에 λ„£μ„λ•Œ 값이 ν‚€ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λΌλŠ” 것이 보μž₯λ˜μ§€ μ•ŠλŠ”λ‹€. λ”°λΌμ„œ λ§΅μ—μ„œ κ°€μ Έμ˜¬λ•ŒλŠ” cast λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ 이 객체 μ°Έμ‘°λ₯Ό class 객체가 κ°€λ¦¬ν‚€λŠ” T νƒ€μž…μœΌλ‘œ 동적 λ³€ν™˜ν•˜κ³  μžˆλ‹€ 뢀뢄에 λŒ€ν•΄ μ•Œμ•„λ³΄μž {% endhint %}

이 μ„€λͺ…은 Class.cast() λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ Favorites ν΄λž˜μŠ€μ—μ„œ νƒ€μž… μ•ˆμ „μ„±μ„ 보μž₯ν•˜λŠ” 방법

  1. 값을 Object νƒ€μž…μœΌλ‘œ μ €μž₯:
    • Favorites 클래슀의 favorites λ§΅μ—μ„œλŠ” ν‚€λ‘œ Class<T> νƒ€μž…μ„, κ°’μœΌλ‘œ Object νƒ€μž…μ„ μ‚¬μš©ν•˜κ³  μžˆλ‹€.
    • μ—¬κΈ°μ„œ Object νƒ€μž…μ€ λͺ¨λ“  νƒ€μž…μ˜ 객체λ₯Ό μ €μž₯ν•  수 μžˆμ§€λ§Œ, νƒ€μž…μ΄ λ§žμ§€ μ•ŠλŠ” 값이 μ €μž₯될 κ°€λŠ₯성이 μžˆλ‹€.
  2. νƒ€μž… μ•ˆμ „μ„± 문제:
    • 맡의 값이 Object둜 μ €μž₯λ˜λ―€λ‘œ, νŠΉμ • 킀와 μΌμΉ˜ν•˜λŠ” νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ§Œ μ €μž₯λ˜λ„λ‘ 보μž₯ν•  방법이 μ—†λ‹€.
    • 예λ₯Ό λ“€μ–΄, Class<String> νƒ€μž…μ˜ ν‚€λ₯Ό μ‚¬μš©ν•΄ String을 μ €μž₯ν–ˆμ–΄μ•Ό ν•˜μ§€λ§Œ, λ‹€λ₯Έ νƒ€μž…μ˜ 값을 μ‹€μˆ˜λ‘œ μ €μž₯ν•  수 μžˆλŠ” μœ„ν—˜μ΄ μžˆλ‹€.
  3. Class.cast()의 μ—­ν• :
    • Class.cast() λ©”μ„œλ“œλŠ” 동적 ν˜• λ³€ν™˜μ„ μ œκ³΅ν•˜μ—¬, λ§΅μ—μ„œ 값을 κ°€μ Έμ˜¬ λ•Œ Class<T> 킀에 μ§€μ •λœ νƒ€μž…μœΌλ‘œ μ•ˆμ „ν•˜κ²Œ λ³€ν™˜ν•΄μ€€λ‹€.
    • 예λ₯Ό λ“€μ–΄, Class<String> ν‚€λ₯Ό μ‚¬μš©ν•˜μ—¬ κ°€μ Έμ˜€λŠ” 경우, Class.cast()λŠ” λ°˜ν™˜λ˜λŠ” 값이 String인지 ν™•μΈν•˜κ³  맞으면 κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•œλ‹€. λ§Œμ•½ String이 μ•„λ‹ˆλ©΄ ClassCastException이 λ°œμƒν•œλ‹€.
  4. Favorites 클래슀의 λ™μž‘ 원리:
    • putFavorite λ©”μ„œλ“œμ—μ„œλŠ” Class<T> 킀와 T νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό ν•¨κ»˜ 전달받아 μ €μž₯ν•œλ‹€. μ΄λ•Œ 맡은 Object νƒ€μž…μœΌλ‘œ μ €μž₯ν•˜μ§€λ§Œ, getFavorite λ©”μ„œλ“œλŠ” Class.cast()λ₯Ό 톡해 T둜 λ°˜ν™˜λ˜λ―€λ‘œ νƒ€μž… μ•ˆμ „μ„±μ΄ ν™•λ³΄λœλ‹€.
public <T> T getFavorite(Class<T> type) {
    return type.cast(favorites.get(type));  // T νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•΄ μ•ˆμ „ν•˜κ²Œ λ°˜ν™˜
}
  • type.cast(favorites.get(type))λŠ” favorites.get(type)으둜 μ–»μ–΄μ˜¨ Object νƒ€μž…μ˜ 값을 type이 κ°€λ¦¬ν‚€λŠ” νƒ€μž…μœΌλ‘œ ν˜•λ³€ν™˜ν•œλ‹€.
  • type이 String.class일 λ•Œ cast()λŠ” Object 값을 String으둜 λ³€ν™˜ν•˜κ³ , Integer.class일 λ•ŒλŠ” Integer둜 λ³€ν™˜ν•œλ‹€.

Class.cast() λ©”μ„œλ“œλ₯Ό ν™œμš©ν•¨μœΌλ‘œμ¨ Favorites ν΄λž˜μŠ€λŠ” μ—¬λŸ¬ νƒ€μž…μ˜ 객체λ₯Ό Map<Class<?>, Object>에 μ•ˆμ „ν•˜κ²Œ μ €μž₯ν•˜κ³  κΊΌλ‚Ό 수 μžˆλ‹€. 이λ₯Ό 톡해 동적 ν˜• λ³€ν™˜ κ³Όμ •μ—μ„œ νƒ€μž… μ•ˆμ •μ„±μ„ μœ μ§€ν•˜κ³ , 잘λͺ»λœ ν˜•λ³€ν™˜ μ‹œ ClassCastException을 λ°œμƒμ‹œμΌœ 였λ₯˜λ₯Ό λ°©μ§€ν•  수 μžˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈ ν™œμš©

 public static void main(String[] args) {
     Favorites f = new Favorites();
        
     f.putFavorite(String.class, "Java");
     f.putFavorite(Integer.class, 0xcafebabe);
     f.putFavorite(Class.class, Favorites.class);
       
     String favoriteString = f.getFavorite(String.class);
     int favoriteInteger = f.getFavorite(Integer.class);
     Class<?> favoriteClass = f.getFavorite(Class.class);
        
     // Java cafebabe Favorites 좜λ ₯
     System.out.printf("%s %x %s%n", favoriteString,
                favoriteInteger, favoriteClass.getName()); 
 }

μ΄λ ‡κ²Œ Favorites μΈμŠ€ν„΄μŠ€λŠ” νƒ€μž… μ•ˆμ „ν•˜λ©° 일반적인 λ§΅κ³Ό 달리 μ—¬λŸ¬ κ°€μ§€ νƒ€μž…μ˜ μ›μ†Œλ₯Ό 담을 수 있기 λ•Œλ¬Έμ—, νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλΌκ³  ν•  수 μžˆλ‹€.

4) 일반 μ œλ„€λ¦­κ³Ό νƒ€μž… μ•ˆμ • 이쀑 μ»¨ν…Œμ΄λ„ˆ 차이점 ν•œ 번 더 정리

{% hint style="info" %} μ œλ„€λ¦­ νƒ€μž…μ„ μ‚¬μš©ν•œ 일반적인 μ»¨ν…Œμ΄λ„ˆ(Set<E>, Map<K,V>)와 νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ νŒ¨ν„΄μ˜ 차이점은 λ§€κ°œλ³€μˆ˜ν™”λ˜λŠ” λŒ€μƒμ΄ μ»¨ν…Œμ΄λ„ˆ μžμ‹ μΈμ§€, ν‚€μΈμ§€μ—μ„œ λ‚˜μ˜¨λ‹€. {% endhint %}

일반적인 μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆ (Set<E>, Map<K,V>)의 λ§€κ°œλ³€μˆ˜ν™”

μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆμΈ Set<E>, Map<K,V>λŠ” μ»¨ν…Œμ΄λ„ˆ 자체의 ꡬ쑰λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•œλ‹€.

즉, νŠΉμ • νƒ€μž…μ˜ μ›μ†Œλ₯Ό λ‹΄λŠ” ꡬ쑰둜 μ»¨ν…Œμ΄λ„ˆλ₯Ό μ„€μ •ν•˜κ³ , 각 μ»¨ν…Œμ΄λ„ˆμ— μ •μ˜λœ νƒ€μž… λ§€κ°œλ³€μˆ˜μ— 따라 담을 수 μžˆλŠ” μ›μ†Œ νƒ€μž…μ΄ κ³ μ •λœλ‹€.

  • μ˜ˆμ‹œ:

    Set<String> stringSet = new HashSet<>();  // String νƒ€μž… μ›μ†Œλ§Œ μ €μž₯ κ°€λŠ₯
    Set<Integer> intSet = new HashSet<>();    // Integer νƒ€μž… μ›μ†Œλ§Œ μ €μž₯ κ°€λŠ₯
    
    Map<String, Integer> map = new HashMap<>(); // ν‚€λŠ” String, 값은 Integer νƒ€μž…μœΌλ‘œ κ³ μ •
    • Set<E>μ—μ„œ EλŠ” ν•΄λ‹Ή Set이 담을 μ›μ†Œμ˜ νƒ€μž…μ„ λ‚˜νƒ€λ‚΄λ©°, 이 μ»¨ν…Œμ΄λ„ˆμ— λ‹€λ₯Έ νƒ€μž…μ˜ 값을 넣을 수 μ—†λ‹€.
    • Map<K,V>μ—μ„œ K와 VλŠ” 각각 킀와 κ°’μ˜ νƒ€μž…μ„ λ‚˜νƒ€λ‚΄λ©°, 이 Map은 νŠΉμ • νƒ€μž…μ˜ 킀와 κ°’λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

λ”°λΌμ„œ, 일반적인 μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆμ—μ„œ λ§€κ°œλ³€μˆ˜ν™”λ˜λŠ” λŒ€μƒμ€ μ»¨ν…Œμ΄λ„ˆ μžμ²΄μ΄λ‹€. Set이든 Map이든, νŠΉμ • νƒ€μž…μœΌλ‘œ μ œν•œλœ ν•˜λ‚˜μ˜ νƒ€μž…μ„ λ‹΄κΈ° μœ„ν•œ 섀정을 ν•΄μ£ΌλŠ” 것이닀.


νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ νŒ¨ν„΄

νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ νŒ¨ν„΄μ€ μ»¨ν…Œμ΄λ„ˆμ— λ‹€μ–‘ν•œ νƒ€μž…μ˜ 객체λ₯Ό 담을 수 μžˆλ„λ‘ μ„€κ³„λœ νŒ¨ν„΄μ΄λ‹€.

이 νŒ¨ν„΄μ—μ„œλŠ” μ œλ„€λ¦­ ν‚€(Class<T>)λ₯Ό μ‚¬μš©ν•΄ μ»¨ν…Œμ΄λ„ˆ μ•ˆμ— μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ μ›μ†Œλ₯Ό μ•ˆμ „ν•˜κ²Œ μ €μž₯ν•˜κ³  μ‘°νšŒν•  수 μžˆλ‹€.

  • νŠΉμ§•:

    • μ»¨ν…Œμ΄λ„ˆ μžμ²΄κ°€ μ•„λ‹Œ, ν‚€λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•˜μ—¬ μ»¨ν…Œμ΄λ„ˆμ— μ—¬λŸ¬ νƒ€μž…μ„ 담을 수 있게 ν•œλ‹€.
    • 각 킀에 λŒ€ν•΄ ν•΄λ‹Ή 킀와 μΌμΉ˜ν•˜λŠ” νƒ€μž…μ˜ 값이 μ €μž₯λ˜λ―€λ‘œ νƒ€μž… μ•ˆμ „μ„±μ„ μœ μ§€ν•œλ‹€.
  • μ˜ˆμ‹œ μ½”λ“œ:

    public class Favorites {
        private Map<Class<?>, Object> favorites = new HashMap<>();
    
        public <T> void putFavorite(Class<T> type, T instance) {
            favorites.put(type, instance);
        }
    
        public <T> T getFavorite(Class<T> type) {
            return type.cast(favorites.get(type));
        }
    }
    
    // μ‚¬μš© μ˜ˆμ‹œ
    Favorites favorites = new Favorites();
    favorites.putFavorite(String.class, "Hello, world!");  // String νƒ€μž… μ €μž₯
    favorites.putFavorite(Integer.class, 123);             // Integer νƒ€μž… μ €μž₯
    
    String favoriteString = favorites.getFavorite(String.class); // μ•ˆμ „ν•˜κ²Œ String νƒ€μž…μœΌλ‘œ 꺼냄
    Integer favoriteInteger = favorites.getFavorite(Integer.class); // μ•ˆμ „ν•˜κ²Œ Integer νƒ€μž…μœΌλ‘œ 꺼냄
    • Favorites ν΄λž˜μŠ€λŠ” μ—¬λŸ¬ νƒ€μž…μ˜ 값을 담을 수 μžˆμ§€λ§Œ, Class<T> νƒ€μž… ν‚€λ₯Ό 톡해 각 κ°’μ˜ νƒ€μž…μ„ μ‹λ³„ν•˜κ³  νƒ€μž…μ— 따라 μ•ˆμ „ν•˜κ²Œ μ‘°νšŒν•  수 μžˆλ‹€.
    • putFavoriteκ³Ό getFavorite λ©”μ„œλ“œλŠ” μ œλ„€λ¦­ ν‚€λ₯Ό 톡해 κ°’μ˜ νƒ€μž…μ„ 보μž₯ν•©λ‹ˆλ‹€. 이 λ°©μ‹μœΌλ‘œ ν•˜λ‚˜μ˜ μ»¨ν…Œμ΄λ„ˆμ— μ—¬λŸ¬ νƒ€μž…μ˜ 객체λ₯Ό μ €μž₯ν•  수 μžˆλ‹€.

비ꡐ:

  • 일반 μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆλŠ” ν•˜λ‚˜μ˜ νƒ€μž…λ§Œμ„ λ§€κ°œλ³€μˆ˜ν™”ν•˜μ—¬ 동일 νƒ€μž… μ›μ†Œλ“€λ§Œ λ‹΄λŠ” μš©λ„λ‘œ μ‚¬μš©ν•œλ‹€.
  • νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλŠ” ν‚€(Class<T>)λ₯Ό 톡해 μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ 객체λ₯Ό λ‹΄κ³  관리할 수 μžˆλ„λ‘ ν•˜λ‚˜μ˜ μ»¨ν…Œμ΄λ„ˆλ‘œ μ—¬λŸ¬ νƒ€μž…μ„ μ•ˆμ „ν•˜κ²Œ κ΄€λ¦¬ν•œλ‹€.

결둠적으둜, μ œλ„€λ¦­ μ»¨ν…Œμ΄λ„ˆλŠ” μ»¨ν…Œμ΄λ„ˆ 자체의 νƒ€μž…μ„ λ§€κ°œλ³€μˆ˜ν™”ν•˜κ³ , νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλŠ” ν‚€λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•˜μ—¬ λ‹€μ–‘ν•œ νƒ€μž…μ„ μ•ˆμ „ν•˜κ²Œ 관리할 수 μžˆλ„λ‘ ν•œλ‹€.

2. νƒ€μž… μ•ˆμ „ 이쀑 μ»¨ν…Œμ΄λ„ˆμ˜ ν•œκ³„

1) μ•…μ˜μ μΈ ν΄λΌμ΄μ–ΈνŠΈκ°€ Class 객체λ₯Ό μ œλ„€λ¦­μ΄ μ•„λ‹Œ 둜 νƒ€μž…μœΌλ‘œ λ„˜κΈ°λ©΄ Favorites μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž… μ•ˆμ „μ„±μ΄ μ‰½κ²Œ κΉ¨μ§„λ‹€.

μ•„λž˜ μ½”λ“œμ—μ„œλŠ” Class 둜 νƒ€μž…μœΌλ‘œ λ‹€μ‹œ μΊμŠ€νŒ…ν•˜μ—¬ μ „λ‹¬ν–ˆμœΌλ‹ˆ, 컴파일 νƒ€μž„μ—μ„œλŠ” 문제 없이 Map 에 μ €μž₯이 λœλ‹€. 이후 κΊΌλ‚΄μ˜¬λ•Œ String 객체λ₯Ό Integer 둜 μΊμŠ€νŒ… ν•˜λ € ν•˜λ‹ˆ λŸ°νƒ€μž„μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€.

f.putFavorite((Class)Integer.class, "λ¬Έμžμ—΄");
int result = f.getFavorite(Integer.class);  // ClassCastException
  • μœ„μ™€ 같이 μ•…μ˜μ μœΌλ‘œ (Class)와 같은 μΊμŠ€νŒ…μ„ 톡해 λ‘œνƒ€μž…μ„ μ‚¬μš©ν•˜λŠ” 것에 λŒ€ν•œ 취약점이 μžˆλ‹€.
  • κ·Έλƒ₯ μ‹€ν–‰ν•˜λ©΄, λŸ°νƒ€μž„μ— ClassCastException을 λ§Œλ‚˜κ²Œ 될 것이닀.

첨고둜 μ‹€μ œ κ°œλ°œν• λ•ŒλŠ” 컴파일 κ³Όμ •μ—μ„œ 비검사 κ²½κ³ κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ—, μ§€μΌœλ§Œ μ§„λ‹€λ©΄ λŸ°νƒ€μž„μ— νƒ€μž… μ•ˆμ „μ„±μ΄ 보μž₯될 것이닀.

이처럼 μΈμŠ€ν„΄μŠ€κ°€ νƒ€μž… λΆˆλ³€μ‹μ„ μ–΄κΈ°λŠ” 일이 없도둝 보μž₯ν•˜λ €λ©΄, λ‹€μŒκ³Ό 같이 동적 ν˜•λ³€ν™˜(cast)을 톡해 인수둜 μ£Όμ–΄μ§„ instance 의 νƒ€μž…μ΄ type 으둜 λͺ…μ‹œν•œ νƒ€μž…κ³Ό 같은지 ν™•μΈν•˜λ©΄ λœλ‹€.

 public <T> void putFavorite(Class<T> type, T instance) {
      favorites.put(Objects.requireNonNull(type), type.cast(instance));
 }

ν™œμš©

java.util.Collections 에 checkedSet(), checkedList(), checkedMap() λ©”μ„œλ“œλ“€λ„ ν•΄λ‹Ή 방식을 μ μš©ν•œ μ»¬λ ‰μ…˜ λž˜νΌλ“€μ΄λ‹€. ν•΄λ‹Ή ν΄λž˜μŠ€λ“€μ€ λͺ¨λ‘ CheckedCollection 을 상속 λ°›μ•˜κ³ , typeCheck λ©”μ„œλ“œλ₯Ό 톡해 μΆ”κ°€ μ—°μ‚°μ‹œμ— νƒ€μž…μ„ μ²΄ν¬ν•˜μ—¬ μ•ˆμ „μ„±μ„ 보μž₯ν•œλ‹€.

νƒ€μž… 검증을 톡해 νƒ€μž… μ•ˆμ „μ„±μ„ μ§€ν‚€λŠ” 방식은 μ œλ„€λ¦­ νƒ€μž…κ³Ό 동적 ν˜•λ³€ν™˜(cast)을 ν•¨κ»˜ μ‚¬μš©ν•˜μ—¬ μ»¬λ ‰μ…˜μ΄ ν—ˆμš©λœ νƒ€μž… μ™Έμ˜ κ°’μœΌλ‘œ μ˜€μ—Όλ˜μ§€ μ•Šλ„λ‘ λ°©μ§€ν•  수 μžˆλ‹€. Collections.checkedList() 등도 같은 μ›λ¦¬λ‘œ λ™μž‘ν•˜μ—¬, λ‹€μ–‘ν•œ νƒ€μž…μ„ λ‹€λ£¨λŠ” Java ν”„λ‘œκ·Έλž¨μ—μ„œ 예기치 λͺ»ν•œ νƒ€μž… 였λ₯˜λ₯Ό λ§‰μ•„μ£ΌλŠ” μ€‘μš”ν•œ κΈ°λŠ₯을 ν•œλ‹€.

2) 싀체화 λΆˆκ°€ νƒ€μž…μ—λŠ” μ‚¬μš© ν•  수 μ—†λ‹€λŠ” 것이닀.

λ‹€μ‹œ 말해, κ·ΈλŸ¬λ‹ˆκΉŒ, Stringμ΄λ‚˜ String[]은 μ €μž₯ν•  수 μžˆμ§€λ§Œ, List<String>은 μ €μž₯ν•  수 μ—†λ‹€. List을 μ €μž₯ν•˜λ €λŠ” μ½”λ“œλŠ” μ»΄νŒŒμΌλ˜μ§€ μ•Šμ„ 것이닀.

{% hint style="info" %} List<E>λŠ” 싀체화 λΆˆκ°€ νƒ€μž…μ΄λΌλŠ” 말의 뜻 {% endhint %}

μžλ°”μ—μ„œ μ œλ„€λ¦­ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€ν™”(instantiation)에 κ΄€ν•œ 것이닀. 이것은 μ œλ„€λ¦­ νƒ€μž…μ΄ λŸ°νƒ€μž„ μ‹œμ— μ‹€μ œ νƒ€μž… 정보λ₯Ό μœ μ§€ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

μ œλ„€λ¦­μ€ 컴파일 μ‹œμ—λ§Œ μœ νš¨ν•˜κ³  λŸ°νƒ€μž„μ—λŠ” μ†Œκ±°(erasure)λœλ‹€. λ”°λΌμ„œ μ»΄νŒŒμΌλŸ¬λŠ” μ œλ„€λ¦­ νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μ½”λ“œλ₯Ό κ²€μ‚¬ν•˜μ§€λ§Œ, λŸ°νƒ€μž„μ—λŠ” μ œλ„€λ¦­ νƒ€μž…μ˜ μ‹€μ œ νƒ€μž… 정보λ₯Ό μ œκ±°ν•˜μ—¬ λͺ¨λ“  μ œλ„€λ¦­ νƒ€μž…μ„ μ›μ‹œ νƒ€μž…(raw type)으둜 λ³€ν™˜ν•œλ‹€. μ΄λŠ” ν˜Έν™˜μ„± 및 μ—­ν˜Έν™˜μ„±μ„ μœ μ§€ν•˜κΈ° μœ„ν•œ 것이닀.

κ·Έ 결과둜 μ œλ„€λ¦­ νƒ€μž…μ— λŒ€ν•œ μ‹€μ²΄ν™”λœ νƒ€μž… μ •λ³΄λŠ” λŸ°νƒ€μž„μ— μ‚¬μš©ν•  수 μ—†λ‹€. λ”°λΌμ„œ List<String>κ³Ό 같은 μ œλ„€λ¦­ νƒ€μž…μ€ λŸ°νƒ€μž„μ— List둜만 μΈμ‹λœλ‹€. 이것이 "List<String>이 싀체화 λΆˆκ°€ νƒ€μž…"μ΄λΌλŠ” 말의 μ˜λ―Έλ‹€.

싀체화 λΆˆκ°€ νƒ€μž…μ€ λ¦¬ν”Œλ ‰μ…˜(reflection)을 μ‚¬μš©ν•˜μ—¬ μ œλ„€λ¦­ νƒ€μž…μ˜ μ‹€μ œ νƒ€μž… 정보λ₯Ό λ™μ μœΌλ‘œ μΆ”μΆœν•˜λŠ” 것이 λΆˆκ°€λŠ₯ν•˜λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. λ”°λΌμ„œ λŸ°νƒ€μž„μ—μ„œλŠ” μ œλ„€λ¦­ νƒ€μž…μ˜ νŒŒλΌλ―Έν„°ν™”λœ νƒ€μž… 정보λ₯Ό μ‚¬μš©ν•˜λŠ” 것은 μ–΄λ €μ›Œμ§„λ‹€. ν•˜μ§€λ§Œ 이것이 컴파일 μ‹œμ—λŠ” μ œλ„€λ¦­ νƒ€μž…μ˜ μ•ˆμ „μ„±μ„ 보μž₯ν•˜λŠ” 이유 쀑 ν•˜λ‚˜μ΄λ‹€.

{% hint style="info" %} μŠ€ν”„λ§μ—μ„œλŠ” ParameterizedTypeReferenceλΌλŠ” 클래슀 {% endhint %}

μš°νšŒν•˜κΈ° μœ„ν•œ λ°©λ²•μœΌλ‘œλŠ” 슈퍼 νƒ€μž… 토큰을 μ‚¬μš©ν•  수 μžˆλ‹€. 슈퍼 νƒ€μž…μ„ ν† ν°μœΌλ‘œ μ‚¬μš©ν•œλ‹€λŠ” λœ»μ΄λ‹€.μŠ€ν”„λ§μ—μ„œλŠ” ParameterizedTypeReferenceλΌλŠ” 클래슀둜 미리 κ΅¬ν˜„ν•΄λ†“μ•˜λ‹€.

Favirotes f = new Favorites();

List<String> pets = Arrays.asList("κ°•μ•„μ§€", "고양이");
f.putFavorite(new TypeRef<List<String>>(){}, pets);
List<String> list = f.getFavorite(new TypeRef<List<String>>(){});

μœ„μ²˜λŸΌ μ΄μš©ν•˜μ—¬ ν•΄κ²°ν•œλ‹€.

좜처 : https://soft-dino.tistory.com/62

μŠ€ν”„λ§μ˜ RestTemplate을 μ‚¬μš©ν•˜μ—¬ HTTP μš”μ²­μ„ 보내고, 응닡을 받을 λ•Œ μ œλ„€λ¦­ νƒ€μž…μ„ μœ μ§€ν•˜κ³  싢은 κ²½μš°μ— μ‚¬μš©ν•  수 μžˆλ‹€.

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class ParameterizedTypeReferenceExample {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<String> response = restTemplate.getForEntity("https://api.example.com/data", String.class);
        String body = response.getBody();
        System.out.println("Response body: " + body);

        // μ œλ„€λ¦­ νƒ€μž…μ„ μœ μ§€ν•˜κΈ° μœ„ν•΄ ParameterizedTypeReference μ‚¬μš©
        ResponseEntity<List<MyObject>> listResponse = restTemplate.exchange(
            "https://api.example.com/data",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<List<MyObject>>() {}
        );
        List<MyObject> dataList = listResponse.getBody();
        System.out.println("Response body with ParameterizedTypeReference: " + dataList);
    }
}

μœ„μ˜ μ˜ˆμ‹œμ—μ„œλŠ” RestTemplate을 μ‚¬μš©ν•˜μ—¬ GET μš”μ²­μ„ 보내고 응닡을 λ°›λŠ”λ‹€. 첫 번째 μš”μ²­μ€ λ‹¨μˆœν•œ λ¬Έμžμ—΄μ„ λ°›μ•„μ˜¨λ‹€.

ν•˜μ§€λ§Œ 두 번째 μš”μ²­μ€ List<MyObject>와 같은 μ œλ„€λ¦­ νƒ€μž…μ„ λ°›μ•„μ˜¨λ‹€. 이 λ•Œ ParameterizedTypeReferenceλ₯Ό μ‚¬μš©ν•˜μ—¬ μ œλ„€λ¦­ νƒ€μž… 정보λ₯Ό μœ μ§€ν•œλ‹€.

μ£Όμ˜μ‚¬ν•­

{% hint style="danger" %} ParameterizedTypeReferenceλ₯Ό μ‚¬μš©ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•  점은 읡λͺ… 클래슀λ₯Ό μƒμ„±ν•œλ‹€λŠ” 점이닀. {% endhint %}

μ΄λŠ” 읡λͺ… 클래슀λ₯Ό μƒμ„±ν•˜λŠ” κ²ƒμ΄λ―€λ‘œ ν•΄λ‹Ή 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” ν•˜λ‚˜λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€. λ”°λΌμ„œ λ™μΌν•œ μ œλ„€λ¦­ νƒ€μž…μ— λŒ€ν•΄ μ—¬λŸ¬ 번 μ‚¬μš©ν•˜λ €λ©΄ 맀번 μƒˆλ‘œμš΄ ParameterizedTypeReference μΈμŠ€ν„΄μŠ€λ₯Ό 생성해야 ν•œλ‹€.

3. ν•œμ •μ  νƒ€μž… 토큰을 μ΄μš©ν•œ νƒ€μž… μ œν•œ

νƒ€μž… ν† κ·Όμ΄λž€?

νƒ€μž… 토큰은 μ œλ„€λ¦­ νƒ€μž… 정보λ₯Ό λŸ°νƒ€μž„μ— μ•ˆμ „ν•˜κ²Œ ν™œμš©ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜λŠ” 객체이닀. 주둜 Class<T>λ₯Ό νƒ€μž… ν† ν°μœΌλ‘œ μ‚¬μš©ν•˜μ—¬, νŠΉμ • νƒ€μž…μ˜ 정보λ₯Ό 담은 Class 객체λ₯Ό ν‚€λ‘œ ν™œμš©ν•œλ‹€. 이λ₯Ό 톡해 컴파일 μ‹œμ μ—μ„œ νŠΉμ • νƒ€μž…μ„ μ§€μ •ν•˜κ³ , λŸ°νƒ€μž„μ— ν•΄λ‹Ή νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μ•ˆμ „ν•˜κ²Œ λ‹€λ£° 수 있게 λœλ‹€. 예λ₯Ό λ“€μ–΄ Map<Class<?>, Object> ν˜•νƒœλ‘œ μ—¬λŸ¬ νƒ€μž…μ„ μ•ˆμ „ν•˜κ²Œ λ‹΄λŠ” μ»¨ν…Œμ΄λ„ˆλ₯Ό κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•˜λ‹€.

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class Favorites {
    // Class<?> νƒ€μž…μ„ ν‚€λ‘œ ν•˜κ³  Object νƒ€μž…μ„ κ°’μœΌλ‘œ κ°€μ§€λŠ” λ§΅
    private Map<Class<?>, Object> favorites = new HashMap<>();

    // νƒ€μž… 토큰을 μ‚¬μš©ν•΄ 객체 μ €μž₯ (T νƒ€μž… μΈμŠ€ν„΄μŠ€)
    public <T> void putFavorite(Class<T> type, T instance) {
        favorites.put(Objects.requireNonNull(type), instance);
    }

    // νƒ€μž… 토큰을 μ‚¬μš©ν•΄ 객체 λ°˜ν™˜, μ €μž₯된 νƒ€μž…κ³Ό λ§€ν•‘ν•˜μ—¬ λ°˜ν™˜
    public <T> T getFavorite(Class<T> type) {
        return type.cast(favorites.get(type));
    }

    public static void main(String[] args) {
        Favorites f = new Favorites();

        // 각 νƒ€μž…λ³„λ‘œ Classλ₯Ό νƒ€μž… ν† ν°μœΌλ‘œ μ‚¬μš©ν•΄ μ €μž₯
        f.putFavorite(String.class, "Java");
        f.putFavorite(Integer.class, 42);
        f.putFavorite(Class.class, Favorites.class);

        // νƒ€μž… ν† ν°μœΌλ‘œ μ•ˆμ „ν•˜κ²Œ 객체λ₯Ό 꺼냄
        String favoriteString = f.getFavorite(String.class);
        int favoriteInteger = f.getFavorite(Integer.class);
        Class<?> favoriteClass = f.getFavorite(Class.class);

        // 좜λ ₯
        System.out.printf("%s %d %s%n", favoriteString, favoriteInteger, favoriteClass.getName());
    }
}

πŸ”– ν•œμ •μ  νƒ€μž… ν† ν°μ΄λž€?
ν•œμ •μ  νƒ€μž… λ§€κ°œλ³€μˆ˜( E extends Delayed )λ‚˜ ν•œμ •μ  μ™€μΌλ“œμΉ΄λ“œ( ? extends Delayed )을 μ‚¬μš©ν•˜μ—¬ ν‘œν˜„ κ°€λŠ₯ν•œ νƒ€μž…μ„ μ œν•œν•˜λŠ” 토큰

Favoritesκ°€ μ–΄λ–€ Class 객체든 λ°›μ•„λ“€μ΄λ―€λ‘œ λΉ„ν•œμ •μ  νƒ€μž… 토큰이라 ν•  수 μžˆλ‹€. 이 λ©”μ„œλ“œλ“€μ΄ ν—ˆμš©ν•˜λŠ” νƒ€μž…μ„ μ œν•œν•˜κ³  μ‹Άλ‹€λ©΄, ν•œμ •μ  νƒ€μž… 토큰을 ν™œμš©ν•˜μž.

// λŒ€μƒ μš”μ†Œμ— λ‹¬λ €μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜μ„ λŸ°νƒ€μž„μ— 읽어 μ˜€λŠ” κΈ°λŠ₯
public <T extends Annotation> T getAnnotation(Class<T> annotationType);

이 λ©”μ„œλ“œλŠ” ν† ν°μœΌλ‘œ λͺ…μ‹œν•œ νƒ€μž…μ˜ μ• λ„ˆν…Œμ΄μ…˜μ΄ λŒ€μƒ μš”μ†Œμ— 달렀 μžˆλ‹€λ©΄ κ·Έ μ• λ„ˆν…Œμ΄μ…˜μ„ λ°˜ν™˜ν•˜κ³ , μ—†λ‹€λ©΄ Null을 λ°˜ν™˜ν•œλ‹€. 이λ₯Ό 톡해 μš”μ†Œκ°€ νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆμ²˜λŸΌ λ™μž‘ν•˜κ²Œ ν•œλ‹€.

4. ν•œμ •μ  νƒ€μž… 토큰을 λ°›λŠ” λ©”μ„œλ“œμ— Class<?> νƒ€μž…μ˜ 객체λ₯Ό λ„˜κΈ°λŠ” 법

1) μ• λ„ˆν…Œμ΄μ…˜ APIμ—μ„œ ν•œμ •μ  νƒ€μž… ν† ν°μ˜ μ‚¬μš©

μ• λ„ˆν…Œμ΄μ…˜ API의 AnnotatedElement μΈν„°νŽ˜μ΄μŠ€μ—μ„œ λŸ°νƒ€μž„μ— νŠΉμ • μ• λ„ˆν…Œμ΄μ…˜μ„ κ°€μ Έμ˜€λŠ” λ©”μ„œλ“œμ˜ 예

public <T extends Annotation> T getAnnotation(Class<T> annotationType);
  • μ—¬κΈ°μ„œ annotationType은 ν•œμ •μ  νƒ€μž… ν† ν°μœΌλ‘œ Annotation을 μƒμ†λ°›λŠ” νƒ€μž…λ§Œ 받을 수 μžˆλ„λ‘ μ œν•œν•œλ‹€.
  • 이 λ©”μ„œλ“œλŠ” λͺ…μ‹œλœ νƒ€μž…μ˜ μ• λ„ˆν…Œμ΄μ…˜μ΄ μš”μ†Œμ— 달렀 있으면 ν•΄λ‹Ή μ• λ„ˆν…Œμ΄μ…˜μ„ λ°˜ν™˜ν•˜κ³ , μ—†μœΌλ©΄ null을 λ°˜ν™˜ν•œλ‹€. 이λ₯Ό 톡해 μš”μ†Œκ°€ νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆμ²˜λŸΌ λ™μž‘ν•˜κ²Œ ν•œλ‹€.

2) ν•œμ •μ  νƒ€μž… 토큰을 μ‚¬μš©ν•œ μ•ˆμ „ν•œ ν˜•λ³€ν™˜

일반적으둜 Class<?> νƒ€μž… 객체λ₯Ό Class<? extends Annotation>둜 ν˜•λ³€ν™˜ν•˜λ©΄ 비검사 κ²½κ³ κ°€ λ°œμƒν•œλ‹€. ν•˜μ§€λ§Œ Class 클래슀의 asSubclass λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 동적 νƒ€μž… 검증을 톡해 μ΄λŸ¬ν•œ ν˜•λ³€ν™˜μ„ μ•ˆμ „ν•˜κ²Œ μˆ˜ν–‰ν•  수 μžˆλ‹€.

static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
    Class<?> annotationType = null; // λΉ„ν•œμ •μ  νƒ€μž… 토큰

    try {
        annotationType = Class.forName(annotationTypeName);
    } catch (Exception ex) {
        throw new IllegalArgumentException(ex);
    }

    // `asSubclass`λ₯Ό 톡해 μ•ˆμ „ν•˜κ²Œ ν˜•λ³€ν™˜ν•˜μ—¬ ν•œμ •μ  νƒ€μž… 토큰 적용
    return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}

asSubclass λ©”μ„œλ“œμ˜ μ—­ν• 

  • asSubclass λ©”μ„œλ“œλŠ” 호좜된 Class<?> 객체λ₯Ό μ•ˆμ „ν•˜κ²Œ μ§€μ •λœ Class의 μ„œλΈŒν΄λž˜μŠ€λ‘œ ν˜•λ³€ν™˜ν•œλ‹€.
  • μ΄λ•Œ ν˜•λ³€ν™˜μ— μ„±κ³΅ν•˜λ©΄ 인수둜 받은 클래슀 객체λ₯Ό λ°˜ν™˜ν•˜κ³ , μ‹€νŒ¨ μ‹œ ClassCastException을 λ˜μ§„λ‹€.

✨ μ΅œμ’… 정리

μ»¨ν…Œμ΄λ„ˆ μžμ²΄κ°€ μ•„λ‹Œ ν‚€λ₯Ό νƒ€μž… λ§€κ°œλ³€μˆ˜λ‘œ λ°”κΎΈλ©΄ νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

μ»¬λ ‰μ…˜ API둜 λŒ€ν‘œλ˜λŠ” 일반적인 μ œλ„€λ¦­ ν˜•νƒœμ—μ„œλŠ” ν•œ μ»¨ν…Œμ΄λ„ˆκ°€ λ‹€λ£° 수 μžˆλŠ” νƒ€μž… λ§€κ°œλ³€μˆ˜μ˜ μˆ˜κ°€ κ³ μ •λ˜μ–΄ μžˆλ‹€. ν•˜μ§€λ§Œ μ»¨ν…Œμ΄λ„ˆ μžμ²΄κ°€ μ•„λ‹Œ ν‚€λ₯Ό νƒ€μž… λ§€κ°œλ³€μˆ˜λ‘œ λ°”κΎΈλ©΄ 이런 μ œμ•½μ΄ μ—†λŠ” νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

  • Classλ₯Ό ν‚€λ‘œ μ“°λ©°, μ΄λ ‡κ²Œ μ“°μ΄λŠ” Class 객체λ₯Ό νƒ€μž… 토큰이라 ν•œλ‹€.
    • 직접 κ΅¬ν˜„ν•œ ν‚€ νƒ€μž…λ„ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€.
  • λ°μ΄ν„°λ² μ΄μŠ€μ˜ 행을 ν‘œν˜„ν•œ DatabaseRow νƒ€μž…μ—λŠ” μ œλ„€λ¦­ νƒ€μž…μΈ Column<T>λ₯Ό ν‚€λ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

좜처 및 μ°Έκ³