item 33 Jung inchul - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e μ•„μ΄ν…œ 33λ₯Ό μš”μ•½ν•œ λ‚΄μš© μž…λ‹ˆλ‹€.

μ œλ„€λ¦­μ€ Set<E>, Map<K,V> λ“±μ˜ μ»¬λ ‰μ…˜κ³Ό ThreadLocal<T>, AtomicReference<T> λ“±μ˜ 단일 μ›μ†Œ μ»¨ν…Œμ΄λ„ˆμ—λ„ ν”νžˆ 쓰인닀. μ˜ˆμ»¨λŒ€ Setμ—λŠ” μ›μ†Œμ˜ νƒ€μž…μ„ λœ»ν•˜λŠ” 단 ν•˜λ‚˜μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜λ§Œ 있으면 되며, Mapμ—λŠ” 킀와 κ°’μ˜ νƒ€μž…μ„ λœ»ν•˜λŠ” 2개만 ν•„μš”ν•œ 식이닀.

더 μœ μ—°ν•œ μˆ˜λ‹¨μ΄ ν•„μš”ν•  λ•Œλ„ μ’…μ’… μžˆλ‹€.

λ°μ΄ν„°λ² μ΄μŠ€μ˜ ν–‰(row)은 μž„μ˜ 개수의 μ—΄(column)을 κ°€μ§ˆ 수 μžˆλŠ”λ°, λͺ¨λ“  열을 νƒ€μž… μ•ˆμ „ν•˜κ²Œ μ΄μš©ν•  수 μžˆλ‹€λ©΄ λ©‹μ§ˆ 것이닀.

λ‹€ν–‰νžˆ μ‰¬μš΄ 해법이 μžˆλ‹€.

μ»¨ν…Œμ΄λ„ˆ λŒ€μ‹  ν‚€λ₯Ό λ§€κ°œλ³€μˆ˜ν™”ν•œ λ‹€μŒ, μ»¨ν…Œμ΄λ„ˆμ— 값을 λ„£κ±°λ‚˜ λΊ„ λ•Œ λ§€κ°œλ³€μˆ˜ν™”ν•œ ν‚€λ₯Ό ν•¨κ»˜ μ œκ³΅ν•˜λ©΄ λœλ‹€. 이런 섀계 방식을 νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆ νŒ¨ν„΄μ΄λΌ ν•œλ‹€.

public class Favorite{
    private Map<Class<?>, Object> Favorite = new HashMap<>();
    public  <T> void putFavorite(Class<T> type, T instance){
        Favorite.put(Objects.requireNonNull(type), instance);
    }
    public  <T> T getFavorite(Class<T> type){
        return type.cast(Favorite.get(type));
    }
}
public static void main(String[] args) {
	Favorite f = new Favorite();
	
	f.putFavorite(String.class, "Java");
	f.putFavorite(Integer.class, 0xcafebabe);
	f.putFavorite(Class.class, Favorite.class);

	String Favoritetring = f.getFavorite(String.class);
	int favoriteInteger = f.getFavorite(Integer.class);
	Class<?> favoriteClass = f.getFavorite(Class.class);

	System.out.printf("%s %x %s\n", Favoritetring, favoriteInteger, favoriteClass.getName());
}

Favorite μΈμŠ€ν„΄μŠ€λŠ” νƒ€μž… μ•ˆμ „ν•˜λ‹€. λ”°λΌμ„œ FavoriteλŠ” νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆλΌ ν•  λ§Œν•˜λ‹€.

λΉ„ν•œμ •μ  μ™€μΌλ“œμΉ΄λ“œ νƒ€μž…μ΄λΌ 이 맡 μ•ˆμ— 아무것도 넣을 수 μ—†λ‹€κ³  생각할 수 μžˆμ§€λ§Œ, 사싀은 κ·Έ λ°˜λŒ€λ‹€. μ™€μΌλ“œμΉ΄λ“œ νƒ€μž…μ΄ 쀑첩 λ˜μ—ˆλ‹€λŠ” 점을 깨달아야 ν•œλ‹€.

μ™€μΌλ“œ νƒ€μž…μ΄ μ€‘μ²©λ˜μ—ˆλ‹€λŠ” 말은 무슨 뜻일까?

μ΄λŠ” λͺ¨λ“  ν‚€κ°€ μ„œλ‘œ λ‹€λ₯Έ λ§€κ°œλ³€μˆ˜ν™”νƒ€μž…μΌ 수 μžˆλ‹€λŠ” 뜻으둜, 첫 λ²ˆμ§ΈλŠ” Class, 두 λ²ˆμ§ΈλŠ” Classμ‹μœΌλ‘œ 될 수 μžˆλ‹€.

Favorite ν΄λž˜μŠ€μ—λŠ” μ•Œμ•„λ‘μ–΄μ•Ό ν•  μ œμ•½μ΄ 두 가지 μžˆλ‹€.

  1. μ•…μ˜μ μΈ ν΄λΌμ΄μ–ΈνŠΈκ°€ Class 객체λ₯Ό (μ œλ„€λ¦­μ΄ μ•„λ‹Œ) 둜 νƒ€μž…(μ•„μ΄ν…œ 26)으둜 λ„˜κΈ°λ©΄ Favorite μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž… μ•ˆμ „μ„±μ΄ μ‰½κ²Œ 깨진닀. ν•˜μ§€λ§Œ μ΄λŠ” ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œ μ»΄νŒŒμΌν•  λ•Œ 비검사 κ²½κ³ κ°€ 뜰 것이닀.
public class Favorite {
	private Map<Class<?>, Object> Favorite = new HashMap<>();

	public <T> void putFavorite(Class<T> type, T instance) {
		Favorite.put(Objects.requireNonNull(type), type.cast(instance));
	}
	public <T> T getFavorite(Class<T> type) {
		return type.cast(Favorite.get(type));
	}
}
Favoriteκ°€ `νƒ€μž… λΆˆλ³€μ‹`을 μ–΄κΈ°λŠ” 일이 없도둝 보μž₯ν•˜λ €λ©΄ `putFavorite` λ©”μ„œλ“œμ™€ 같이 `instance`의 νƒ€μž…μ΄ `type`으둜 λͺ…μ‹œν•œ νƒ€μž…κ³Ό 같은지 ν™•μΈν•˜λ©΄ λœλ‹€. 

`java.util.Collections`μ—λŠ” `checkedSet`, `checkedList`, `checkedMap` 같은 λ©”μ„œλ“œκ°€ μžˆλŠ”λ° λ°”λ‘œ 이 방식을 μ μš©ν•œ μ»¬λ ‰μ…˜ λž˜νΌλ“€μ΄λ‹€. 
  1. Favorite 클래슀의 두 번째 μ œμ•½μ€ 싀체화 λΆˆκ°€ νƒ€μž…μ—λŠ” μ‚¬μš©ν•  수 μ—†λ‹€λŠ” 것이닀. λ‹€μ‹œ 말해, 즐겨 μ°ΎλŠ” Stringμ΄λ‚˜ String[]은 μ €μž₯ν•  수 μžˆμ–΄λ„ 즐겨 μ°ΎλŠ” List은 μ €μž₯ν•  수 μ—†λ‹€.

    List<String>을 μ €μž₯ν•˜λ €λŠ” μ½”λ“œλŠ” μ»΄νŒŒμΌλ˜μ§€ μ•Šμ„ 것이닀. List<String>용 Class 객체λ₯Ό 얻을 수 μ—†κΈ° λ•Œλ¬Έμ΄λ‹€. List<String>.class라고 μ“°λ©΄ 문법 였λ₯˜κ°€ λ‚œλ‹€. List<String>κ³Ό List<Integer>λŠ” List.classλΌλŠ” 객체λ₯Ό κ³΅μœ ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

    μ΄λŠ” ν•œμ •μ  νƒ€μž… 토큰을 ν™œμš©ν•˜λ©΄ κ°€λŠ₯ν•˜λ‹€. ν•œμ •μ  νƒ€μž… ν† ν°μ΄λž€ λ‹¨μˆœνžˆ ν•œμ •μ  νƒ€μž… λ§€κ°œλ³€μˆ˜λ‚˜ ν•œμ •μ  μ™€μΌλ“œμΉ΄λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν‘œν˜„ κ°€λŠ₯ν•œ νƒ€μž…μ„ μ œν•œν•˜λŠ” νƒ€μž… 토큰이닀.

    μ• λ„ˆν…Œμ΄μ…˜ API(μ•„μ΄ν…œ 39)λŠ” ν•œμ •μ  νƒ€μž… 토큰을 적극적으둜 μ‚¬μš©ν•œλ‹€.

    public <T extends Annotation> T getAnnotation(Class<T> annotationType);

    μ—¬κΈ°μ„œ annotationTypeμΈμˆ˜λŠ” μ• λ„ˆν…Œμ΄μ…˜ νƒ€μž…μ„ λœ»ν•˜λŠ” ν•œμ •μ  νƒ€μž… 토큰이닀. 이 λ©”μ„œλ“œλŠ” ν† ν°μœΌλ‘œ λͺ…μ‹œν•œ νƒ€μž…μ˜ μ—λ„ˆν…Œμ΄μ…˜μ΄ λŒ€μƒ μš”μ†Œμ— 달렀 μžˆλ‹€λ©΄ κ·Έ μ• λ„ˆν…Œμ΄μ…˜μ„ λ°˜ν™˜ν•˜κ³  μ—†λ‹€λ©΄ null을 λ°˜ν™˜ν•œλ‹€. 즉, μ• λ„ˆν…Œμ΄μ…˜λœ μš”μ†ŒλŠ” κ·Έ ν‚€κ°€ μ• λ„ˆν…Œμ΄μ…˜ νƒ€μž…μΈ, νƒ€μž… μ•ˆμ „ 이쒅 μ»¨ν…Œμ΄λ„ˆμ΄λ‹€.

Class<?> νƒ€μž…μ˜ 객체가 있고, 이λ₯Ό (getAnnotation처럼) ν•œμ •μ  νƒ€μž… 토큰을 λ°›λŠ” λ©”μ„œλ“œμ— λ„˜κΈ°λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒ?

객체λ₯Ό Class<? extends Annotation>으둜 ν˜•λ³€ν™˜ν•  μˆ˜λ„ μžˆμ§€λ§Œ 이 ν˜•λ³€ν™˜μ€ λΉ„κ²€μ‚¬μ΄λ―€λ‘œ μ»΄νŒŒμΌν•˜λ©΄ κ²½κ³ κ°€ 뜬 것이닀. 운 μ’‹κ²Œλ„ Class ν΄λž˜μŠ€κ°€ 이런 ν˜•λ³€ν™˜μ„ μ•ˆμ „ν•˜κ²Œ μˆ˜ν–‰ν•΄μ£ΌλŠ” μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€. λ°”λ‘œ asSubClass λ©”μ„œλ“œλ‘œ, 호좜된 μΈμŠ€ν„΄μŠ€ μžμ‹ μ˜ Class 객체λ₯Ό μΈμˆ˜κ°€ λͺ…μ‹œν•œ 클래슀둜 ν˜•λ³€ν™˜ν•œλ‹€. (ν˜•λ³€ν™˜λœλ‹€λŠ” 것은 이 ν΄λž˜μŠ€κ°€ 인수둜 λͺ…μ‹œν•œ 클래슀의 ν•˜μœ„ ν΄λž˜μŠ€λΌλŠ” λœ»μ΄λ‹€.)

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));
}

정리

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

⚠️ **GitHub.com Fallback** ⚠️