1. ํ์ ์์ ์ด์ข ์ปจํ ์ด๋ ๐
ํ์ ์์ ์ด์ข (Heterogeneous) ์ปจํ ์ด๋๋ ํ ํ์ ์ ๊ฐ์ฒด๋ง ๋ด์ ์ ์๋ ์ปจํ ์ด๋๊ฐ ์๋, ์ฌ๋ฌ ๋ค๋ฅธ ํ์ (์ด์ข )์ ๋ด์ ์ ์๋ ํ์ ์์ ํ ์ปจํ ์ด๋๋ฅผ ๋งํ๋ค.
์ง๊ธ๊น์ง ์ฐ๋ฆฌ๊ฐ ํํ ์๊ณ ์๋ ์ปจํ ์ด๋๋ ํ ๊ฐ์ง ํ์ ๋ง ์ฌ์ฉํ ์ ์๋ ์ปจํ ์ด๋๋ค.
public static void main(String[] args) {
Set<String> names = new HashSet<>();
names.add("amenable");
// names.add(1); // ๋ถ๊ฐ๋ฅ
Set<Integer> numbers = new HashSet<>();
numbers.add(1);
// numbers.add("amenable"); // ๋ถ๊ฐ๋ฅ
}
ํ์ง๋ง, ๊ฒฝ์ฐ์ ๋ฐ๋ผ์๋ ์ด์ข ์ปจํ ์ด๋(= ๊ฐ์ ์ข ์ด ์๋ ํ์ ์ ๋ฃ์ ์ ์๋ ์ปจํ ์ด๋)๊ฐ ํ์ํ๋ค. ์ด๋ฒ ์์ดํ ์ ์ฃผ์ ์ธ ํ์ ์์ ์ด์ข ์ปจํ ์ด๋๋ฅผ ๋ง๋๋ ๋ฐฉ์์ ์์๋ณด์.
2. ๊ตฌํ ๐
ํ์ ์์ ์ด์ข ์ปจํ ์ด๋์ ์์๋ก ํ์ ๋ณ๋ก ์ฆ๊ฒจ ์ฐพ๋ ์ธ์คํด์ค๋ฅผ ์ ์ฅํ๊ณ (= putFavorite ๋ฉ์๋) ๊ฒ์ํ ์ ์๋(= getFavorite ๋ฉ์๋) Favorites ํด๋์ค๋ฅผ ์๊ฐํ ์ ์๋ค.
๊ตฌํ ๋ฐฉ๋ฒ์ '์ปจํ ์ด๋๊ฐ ์๋๋ผ "ํค"๋ฅผ ๋งค๊ฐ๋ณ์ํ ํ์ฌ ๊ตฌํํ๋ ๊ฒ'์ด๋ค.
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));
}
}
๊ทธ๋ฌ๋ฉด ์๋์ ๊ฐ ํ์ ๋ณ๋ก ์ธ์คํด์ค๋ฅผ ์ ์ฅํ๊ณ ๊ฒ์ํ ์ ์๋ค.
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite(String.class, "amenable");
favorites.putFavorite(Integer.class, 1);
String name = favorites.getFavorite(String.class); // amenable
Integer number = favorites.getFavorite(Integer.class); // 1
}
์ฆ, Favorites ์ธ์คํด์ค๋ ํ์ ์์ ํ๊ณ , ์ผ๋ฐ์ ์ธ ๋งต๊ณผ ๋ฌ๋ฆฌ ์ฌ๋ฌ ๊ฐ์ง ํ์ ์ ์์๋ฅผ ๋ด์ ์ ์๊ธฐ ๋๋ฌธ์ Favorites๋ 'ํ์ ์์ ์ด์ข ์ปจํ ์ด๋'๋ผ๊ณ ํ ์ ์๋ค.
์ฉ์ด ํ๋๋ฅผ ์ง๊ณ ๋์ด๊ฐ์๋ฉด ์ปดํ์ผํ์ ํ์ ์ ๋ณด์ ๋ฐํ์ ํ์ ์ ๋ณด๋ฅผ ์์๋ด๊ธฐ ์ํด ๋ฉ์๋๋ค์ด ์ฃผ๊ณ ๋ฐ๋ class ๋ฆฌํฐ๋ด์ ํ์ ํ ํฐ(Type Token)์ด๋ผ ํ๋ค.
class ๋ฆฌํฐ๋ด์ ํ์ ์ Class๊ฐ ์๋ Class<T>์ด๊ณ , String.class์ ํ์ ์ Class<String>, Integer.class์ ํ์ ์ Class<Integer>์ธ ๊ฒ์ด๋ค.
3. ์ ์ฝ ์ฌํญ ๐
์ง๊ธ๊น์ง ํ์ ์ด์ข ์ปจํ ์ด๋์ธ Favorites ํด๋์ค๋ฅผ ์ดํด๋ณด์๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ์์๋์ด์ผ ํ ์ ์ฝ์ด 2๊ฐ์ง ์๋ค.
๐ ์ ์ฝ 1. ์ ์์ ์ธ ํด๋ผ์ด์ธํธ๊ฐ Class ๊ฐ์ฒด๋ฅผ (์ ๋ค๋ฆญ์ด ์๋) ๋ก ํ์ ์ผ๋ก ๋๊ธฐ๋ฉด Favorites ์ธ์คํด์ค์ ํ์ ์์ ์ฑ์ด ์ฝ๊ฒ ๊นจ์ง๋ค.
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));
}
}
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite((Class) String.class, 1);
}
putFavorite ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋ ํด๋์ค์ ํ์ (String, Integer, ...)๋ฅผ ์ค์ ํ์ง ์๊ณ ๊ทธ๋ฅ Class๋ก๋ง ๋๊ธฐ๊ฒ ๋๋ฉด ์ฝ๋์์ ํ์ธํ ์ ์๋ ๊ฒ์ฒ๋ผ instance์ ์๋ฌด ๊ฐ์ด๋ ๋ฃ์ ์ ์๋ค.
์์ํ ์ ์๋ฏ์ด putFavorite ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite((Class) String.class, 1);
String str = favorites.getFavorite(String.class); // ClassCastException
}
Integer ๊ฐ์ ๋ฃ์์ง๋ง ๊ทธ๊ฒ์ String์ผ๋ก ๋ณํํ๋ ค๊ณ ํ๊ธฐ ๋๋ฌธ์ ClassCastException์ด ๋ฐ์ํ๋ค.
ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก๋ putFavorite ๋ฉ์๋์์ ์ธ์๋ก ์ฃผ์ด์ง instance์ ํ์ ์ด type์ผ๋ก ๋ช ์ํ ํ์ ๊ณผ ๊ฐ์์ง ํ์ธํ๋ฉด ๋๋ค.
public class Favorites {
...
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(Objects.requireNonNull(type), type.cast(instance));
}
...
}
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite((Class) String.class, 1); // ClassCastException
String str = favorites.getFavorite(String.class);
}
๊ทธ๋ฌ๋ฉด getFavorite๋ฅผ ์ฌ์ฉํ ๋ ๋ฐํ์ ์๋ฌ๊ฐ ๋๋ ๊ฒ์ด ์๋๋ผ putFavorites์์ ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ์กฐ๊ธ ๋ ๋์ ๋ฐฉ๋ฒ์ด๊ธฐ๋ ํ์ง๋ง ๊ทผ๋ณธ์ ์ผ๋ก ์ปดํ์ผ ํ์์๋ ๋ง์ ์ ์๋ค๋ ํ๊ณ๊ฐ ์๋ค.
๐ ์ ์ฝ 2. ์ค์ฒดํ ๋ถ๊ฐ ํ์ ์๋ ์ฌ์ฉํ ์ ์๋ค.
List.class๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์๋ค.
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite(List.class, List.of(1, 2, 3));
List list = favorites.getFavorite(List.class);
list.forEach(System.out::print); // 123
}
๋ง์ฝ List.of(1, 2, 3)๊ณผ List.of("a", "b", "c")๋ฅผ ๋ฐ๋ก ์ ์ฅํ๊ณ ์ถ์ด์ ์๋์ ๊ฐ์ด ์ด๋ค๋ฉด ๋ค์ ๋์จ ๊ฒ์ด ์์ ๋์จ ๊ฒ์ ๋ฎ์ด์ฐ๊ฒ ๋๋ค.
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite(List.class, List.of(1, 2, 3));
favorites.putFavorite(List.class, List.of("a", "b", "c")); // ๋ฎ์ด์
List list = favorites.getFavorite(List.class);
list.forEach(System.out::print); // abc
}
๊ทธ๋์ ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฐ๋ฉด ๋์ง ์์๊น๋ผ๊ณ ์๊ฐํ ์ ์๋ค.
public static void main(String[] args) {
Favorites favorites = new Favorites();
// ์ฌ์ฉ๋ถ๊ฐ
favorites.putFavorite(List<Integer>.class, List.of(1, 2, 3));
favorites.putFavorite(List<String>.class, List.of("a", "b", "c"));
List list = favorites.getFavorite(List.class);
list.forEach(System.out::print); // abc
}
ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ๋ถ๊ฐ๋ฅํ๋ค. List.class๋ง ์กด์ฌํ๋ ๊ฒ์ด์ง List<Integer>.class, List<String>.class์ ๊ฐ์ ๊ฒ์ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด ์ ์ฝ์ฌํญ์ ๋ํด์๋ ์๋ฒฝํ ๋ง์กฑ์ค๋ฌ์ด ์ฐํ๋ก๋ ์๋ค. ๋ ๊ฐํํฐ(Neal Gafter)๊ฐ ์ ์ํ ์ํผ ํ์ ํ ํฐ(Super Type Token)์ผ๋ก ์ด๋ ์ ๋ ๋ฌธ์ ๋ ํด๊ฒฐํ ์ ์๋ค. ํ์ง๋ง, ์ํผ ํ์ ํ ํฐ๋ ์๋ฒฝํ์ง๋ ์์ผ๋ ์ฃผ์ํด์ ์ฌ์ฉํ๋๋ก ํด์ผ ํ๋ค.
4. ํ์ ์ ํ์ ํ ํฐ ๐
์ง๊ธ๊น์ง ์ดํด๋ณธ ํ์ ํ ํฐ์ ๋นํ์ ์ ์ด๋ค. ์ฆ, getFavorite์ putFavorite๋ ์ด๋ค Class ๊ฐ์ฒด๋ ๋ฐ์๋ค์ผ ์ ์๋ค.
๋๋ก๋ ์ด ๋ฉ์๋๋ค์ด ํ์ฉํ๋ ํ์ ์ ์ ํํ๊ณ ์ถ์ ์ ์๋๋ฐ, ์ด๋ ํ์ ์ ํ์ ํ ํฐ์ ํ์ฉํ ์ ์๋ค. ํ์ ์ ํ์ ํ ํฐ์ด๋ ๋จ์ํ ํ์ ์ ํ์ ๋งค๊ฐ๋ณ์๋ ํ์ ์ ์์ผ๋์นด๋๋ฅผ ์ฌ์ฉํ์ฌ ํํ ๊ฐ๋ฅํ ํ์ ์ ์ ํํ๋ ํ์ ํ ํฐ์ด๋ค.
// FindMe
@Retention(RetentionPolicy.RUNTIME)
public @interface FindMe { }
// MyService
@FindMe
public class MyService { }
// PrintAnnotation
public class PrintAnnotation {
static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
Class<?> annotationType = null;
try {
annotationType = Class.forName(annotationTypeName);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}
}
// ๋ช
์ํ ํด๋์ค์ ๋ช
์ํ ์ ๋ํ
์ด์
์ ์ถ๋ ฅํ๋ ํ
์คํธ ํ๋ก๊ทธ๋จ
public static void main(String[] args) {
System.out.println(getAnnotation(MyService.class, FindMe.class.getName()));
}
asSubclass ๋ฉ์๋๋ ํธ์ถ๋ ์ธ์คํด์ค ์์ ์ Class ๊ฐ์ฒด๋ฅผ ์ธ์๊ฐ ๋ช ์ํ ํด๋์ค๋ก ํ๋ณํํ๋ค. ๊ทธ๋์ asSubclass๋ฅผ ์ฌ์ฉํด์ ํ์ ์ ํ์ ํ ํฐ์ ์์ ํ๊ฒ ํ๋ณํํ ์ ์๋ค.
ํด๋น ๊ธ์ ๋ฐฑ๊ธฐ์ ๋์ '์ดํํฐ๋ธ ์๋ฐ ์๋ฒฝ ๊ณต๋ต'์ ์ฐธ๊ณ ํ์์ต๋๋ค.