item 28 JihoonKim - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

[item28] λ°°μ—΄λ³΄λ‹€λŠ” 리슀트λ₯Ό μ‚¬μš©ν•˜λΌ

λ°°μ—΄κ³Ό μ œλ„€λ¦­ νƒ€μž…μ˜ μ€‘μš”ν•œ 차이

  • 배열은 곡변('ν•¨κ»˜ λ³€ν•œλ‹€')μ΄μ§€λ§Œ, μ œλ„€λ¦­μ€ λΆˆκ³΅λ³€μ΄λ‹€.

    • Subκ°€ Super의 ν•˜μœ„ νƒ€μž…μ΄λ©΄, Sub[]도 Super[]의 ν•˜μœ„ νƒ€μž…μ΄λ‹€.
      Object[] objectArray = new Long[1]; // Long이 Object의 ν•˜μœ„ νƒ€μž…
      objectArray[0] = "Long에 String을 넣을 수 μ—†μ–΄"; // λŸ°νƒ€μž„μ— ArrayStoreException λ°œμƒ
    • μ„œλ‘œ λ‹€λ₯Έ νƒ€μž… Type1, Type2κ°€ μžˆμ„ λ•Œ, List<Type1>은 List<Type2>의 μƒμœ„ νƒ€μž…λ„, ν•˜μœ„ νƒ€μž…λ„ μ•„λ‹ˆλ‹€.(JLS-4.10)
      List<Object> ol = new ArrayList<Long>(); // ν˜Έν™˜λ˜μ§€ μ•ŠλŠ” νƒ€μž…, Compile μ—λŸ¬
      ol.add("Long에 String을 넣을 수 μ—†μ–΄");
  • 배열은 싀체화(reify)λœλ‹€. (JLS-4.7)

    • 배열은 λŸ°νƒ€μž„μ—λ„ μžμ‹ μ΄ λ‹΄κΈ°λ‘œ ν•œ μ›μ†Œμ˜ νƒ€μž…μ„ μΈμ§€ν•˜κ³  ν™•μΈν•œλ‹€λŠ” 것 - ArrayStoreException λ°œμƒλ„ κ°€λŠ₯
      • μ œλ„€λ¦­μ€ νƒ€μž… 정보가 λŸ°νƒ€μž„μ—λŠ” μ†Œκ±°(erasure)λœλ‹€.(JLS-4.6)
        • μ›μ†Œ νƒ€μž…μ„ μ»΄νŒŒμΌνƒ€μž„μ—λ§Œ κ²€μ‚¬ν•˜λ©° λŸ°νƒ€μž„μ—λŠ” μ•Œ 수 μ‘°μ°¨ μ—†λ‹€
        • μ œλ„€λ¦­ 지원 μ „ λ ˆκ±°μ‹œ μ½”λ“œ λŒ€ν•œ ν•˜μœ„ ν˜Έν™˜μ„± λͺ©μ 

μ œλ„€λ¦­ 배열을 μƒμ„±ν•˜μ§€ λͺ»ν•œλ‹€.

  • new List<E>[](μ œλ„€λ¦­ νƒ€μž…), new List<String>[](λ§€κ°œλ³€μˆ˜ν™” νƒ€μž…), new E[](νƒ€μž… λ§€κ°œλ³€μˆ˜) μ‹μœΌλ‘œ μž‘μ„±ν•˜λ©΄ 컴파일 μ—λŸ¬ λ°œμƒν•œλ‹€.
  • κ·Έ μ΄μœ λŠ” νƒ€μž… μ•ˆμ „ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄λ‹€.
    • ν—ˆμš©ν•œλ‹€λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μžλ™ μƒμ„±ν•œ ν˜•λ³€ν™˜ μ½”λ“œμ—μ„œ λŸ°νƒ€μž„μ— ClassCastException이 λ°œμƒν•  수 μžˆμ–΄, μ΄λŠ” μ œλ„€λ¦­ νƒ€μž… μ‹œμŠ€ν…œμ˜ 취지에 μ–΄κΈ‹λ‚œλ‹€.
      List<String>[] stringLists = new List<String>[1]; // (1), 컴파일 μ—λŸ¬ λ°œμƒ, ν•˜μ§€λ§Œ ν—ˆμš©λœλ‹€κ³  κ°€μ •
      List<Integer> intList = List.of(42);              // (2), List.of()λŠ” JDK 9λΆ€ν„° μ‚¬μš© κ°€λŠ₯
      Object[] objects = stringLists;                   // (3)
      objects[0] = intList;                             // (4)
      String s = stringLists[0].get(0);                 // (5), 문제 λ°œμƒ
      • 배열은 κ³΅λ³€μ΄λ‹ˆ, (3)은 (1)μ—μ„œ μƒμ„±ν•œ List<String>의 배열을 Object 배열에 ν• λ‹Ήν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
      • μ œλ„€λ¦­μ€ μ†Œκ±° λ°©μ‹μ΄λ‹ˆ, λŸ°νƒ€μž„μ—List<Integer> μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ€ λ‹¨μˆœ Listκ°€ 되고, List<Integer>[]와 List<String> μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ€ List[]κ°€ λœλ‹€. κ·Έλž˜μ„œ, (4)μ—μ„œλŠ” (2)μ—μ„œ μƒμ„±ν•œ List<Integer>의 μΈμŠ€ν„΄μŠ€λ₯Ό Object λ°°μ—΄μ˜ 첫 μ›μ†Œλ‘œ μ €μž₯해도 ArrayStoreException이 λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€
      • λ¬Έμ œλŠ” (5)μ—μ„œ λ°œμƒν•œλ‹€. List<String> μΈμŠ€ν„΄μŠ€λ§Œ λ‹΄κ² λ‹€κ³  μ„ μ–Έν•œ stringLists 배열에 λ‹€λ₯Έ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€(List<Integer>)κ°€ λ‹΄κ²¨μžˆλŠ”λ°, 첫 μ›μ†Œλ₯Ό κΊΌλ‚΄λ €κ³  ν•œλ‹€. 그리고 이λ₯Ό String으둜 ν˜•λ³€ν™˜ν•˜λŠ”λ°, 이 μ›μ†ŒλŠ” Integer νƒ€μž…μ΄λ―€λ‘œ λŸ°νƒ€μž„μ— ClassCastException이 λ°œμƒ

싀체화 λΆˆκ°€ νƒ€μž…

  • E, List<E>, List<String> 같은 νƒ€μž…μ€ 싀체화 λΆˆκ°€ νƒ€μž…(non-reifiable type, JLS-4.7)이닀.
    • μ»΄νŒŒμΌνƒ€μž„λ³΄λ‹€ λŸ°νƒ€μž„μ— νƒ€μž… 정보λ₯Ό 적게 κ°–λŠ”λ‹€
  • μ†Œκ±° λ©”μ»€λ‹ˆμ¦˜μœΌλ‘œ 인해 λ§€κ°œλ³€μˆ˜ν™” νƒ€μž… κ°€μš΄λ° 싀체화될 수 μžˆλŠ” νƒ€μž…μ€ List<?>와 Map<?,?>같은 λΉ„ν•œμ •μ  μ™€μΌλ“œμΉ΄λ“œ νƒ€μž…λΏ(item26)

λ°°μ—΄λ‘œ ν˜•λ³€ν™˜μ‹œ 였λ₯˜κ°€ λ°œμƒν•œλ‹€λ©΄

μ œλ„€λ¦­ λ°°μ—΄ 생성 였λ₯˜λ‚˜ 비검사 ν˜•λ³€ν™˜ κ²½κ³ κ°€ λœ¨λŠ” 경우 λŒ€λΆ€λΆ„ 배열인 E[] λŒ€μ‹  μ»¬λ ‰μ…˜μΈ List<E>λ₯Ό μ‚¬μš©ν•˜λ©΄ ν•΄κ²°λœλ‹€.

// μ œλ„€λ¦­ μ“°μ§€ μ•Šκ³  κ΅¬ν˜„
public class Chooser {
	public final Object[] choiceArray;
	
	public Chooser(Collection choices) {
		choiceArray = choices.toArray();
	}

	// 이 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” κ³³μ—μ„œλŠ” 맀번 ν˜•λ³€ν™˜μ΄ ν•„μš”
	// λŸ°νƒ€μž„μ— ν˜•λ³€ν™˜ 였λ₯˜μ˜ κ°€λŠ₯μ„±
	public Object choose() {
		Random rnd = ThreadLocalRandom.current();
		return choiceArray[rnd.nextInt(choiceArray.length)];
	}
}
// μ œλ„€λ¦­ κ΅¬ν˜„μ„ μœ„ν•œ μ‹œλ„(컴파일 μ—λŸ¬, κ²½κ³  λ°œμƒ)
public class Chooser<T> {
	public final T[] choiceArray;
	
	public Chooser(Collection<T> choices) {
		// [1] 컴파일 μ—λŸ¬, incompatible types: java.lang.Object[] cannot be converted to T[]
		choiceArray = choices.toArray();
		
		// [2] 'Unchecked Cast' κ²½κ³ , T의 νƒ€μž…μ„ λͺ°λΌ 이 ν˜•λ³€ν™˜μ΄ λŸ°νƒ€μž„μ—λ„ μ•ˆμ „ν•œμ§€ 보μž₯ν•  수 μ—†λ‹€.
		choiceArray = (T[]) choices.toArray();
	}
	// choose methodλŠ” 동일
}
// 리슀트 기반 Chooser (νƒ€μž… μ•ˆμ •μ„± 확보)
public class Chooser<T> {
	public final List<T> choiceList;
	
	public Chooser(Collection<T> choices) {
		choiceList = new ArrayList<>(choices);
	}
	public T choose() {
		Random rnd = ThreadLocalRandom.current();
		return choiceList.get(rnd.nextInt(choiceList.size()));
	}
}

핡심 정리

  • λ°°μ—΄κ³Ό μ œλ„€λ¦­μ€ 맀우 λ‹€λ₯Έ κ·œμΉ™μ΄ μ μš©λœλ‹€.
    • 배열은 '곡변'κ³Ό '싀체화'(λŸ°νƒ€μž„μ— νƒ€μž… μ•ˆμ „)
    • μ œλ„€λ¦­μ€ 'λΆˆκ³΅λ³€'κ³Ό νƒ€μž… 정보 'μ†Œκ±°'(컴파일 νƒ€μž„μ— νƒ€μž… μ•ˆμ „)
  • λ‘˜μ„ μ„žμ–΄ μ“°λ‹€ 컴파일 였λ₯˜λ‚˜ κ²½κ³ λ₯Ό λ§Œλ‚˜λ©΄, κ°€μž₯ λ¨Όμ € 배열을 리슀트둜 λŒ€μ²΄ν•΄λ³΄μž!
⚠️ **GitHub.com Fallback** ⚠️