Language/Java

β˜• μžλ°” μ œλ„€λ¦­(Generics) κ°œλ… & 문법 μ •λ³΅ν•˜κΈ°

인파_ 2023. 1. 17. 08:39

java-Generics

μ œλ„€λ¦­ (Generics) μ΄λž€

μžλ°”μ—μ„œ μ œλ„€λ¦­(Generics)은 ν΄λž˜μŠ€ λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•  데이터 νƒ€μž…μ„ μ™ΈλΆ€μ—μ„œ μ§€μ •ν•˜λŠ” 기법을 μ˜λ―Έν•œλ‹€. κ°μ²΄λ³„λ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ μžλ£Œκ°€ μ €μž₯될 수 μžˆλ„λ‘ ν•œλ‹€.

μžλ°”μ—μ„œ λ°°μ—΄κ³Ό ν•¨κ»˜ 자주 μ“°μ΄λŠ” μžλ£Œν˜•μ΄ 리슀트(List)인데, λ‹€μŒκ³Ό 같이 클래슀 μ„ μ–Έ 문법에 κΊΎμ‡  κ΄„ν˜Έ <> 둜 λ˜μ–΄μžˆλŠ” μ½”λ“œ ν˜•νƒœλ₯Ό ν•œλ²ˆ 쯀은 봀을 것이닀.

ArrayList<String> list = new ArrayList<>();

μ € κΊΎμ‡  κ΄„ν˜Έκ°€ λ°”λ‘œ μ œλ„€λ¦­μ΄λ‹€. κ΄„ν˜Έ μ•ˆμ—λŠ” νƒ€μž…λͺ…을 κΈ°μž¬ν•œλ‹€. 그러면 μ € 리슀트 클래슀 μžλ£Œν˜•μ˜ νƒ€μž…μ€ String νƒ€μž…μœΌλ‘œ μ§€μ •λ˜μ–΄ λ¬Έμžμ—΄ λ°μ΄ν„°λ§Œ λ¦¬μŠ€νŠΈμ— μ μž¬ν•  수 있게 λœλ‹€.

μ•„λž˜ κ·Έλ¦Όκ³Ό 같이 λ°°μ—΄κ³Ό 리슀트의 μ„ μ–Έλ¬Έ ν˜•νƒœλ₯Ό 비ꡐ해보면 μ΄ν•΄ν•˜κΈ° μ‰¬μšΈ 것이닀. μ„ μ–Έν•˜λŠ” ν‚€μ›Œλ“œλ‚˜ 문법 μˆœμ„œκ°€ λ‹€λ₯ΌλΏ, κ²°κ΅­ μžλ£Œν˜•λͺ…을 μ„ μ–Έν•˜κ³  μžλ£Œν˜•μ˜ νƒ€μž…μ„ μ§€μ •ν•œλ‹€λŠ” 점은 κ°™λ‹€κ³  λ³Ό 수 μžˆλ‹€.

java-Generics

이처럼 μ œλ„€λ¦­μ€ λ°°μ—΄μ˜ νƒ€μž…μ„ μ§€μ •ν•˜λ“―μ΄ 리슀트 μžλ£Œν˜• 같은 μ»¬λ ‰μ…˜ ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œμ—μ„œ μ‚¬μš©ν•  λ‚΄λΆ€ 데이터 νƒ€μž…(type)을 νŒŒλΌλ―Έν„°(parameter) μ£Όλ“―이 μ™ΈλΆ€μ—μ„œ μ§€μ •ν•˜λŠ” 이λ₯Έλ°” νƒ€μž…μ„ λ³€μˆ˜ν™” ν•œ κΈ°λŠ₯이라고 μ΄ν•΄ν•˜λ©΄ λœλ‹€.

μš°λ¦¬κ°€ λ³€μˆ˜λ₯Ό μ„ μ–Έν• λ•Œ λ³€μˆ˜μ˜ νƒ€μž…μ„ 지정해주듯이, μ œλ„€λ¦­μ€ 객체(Object)에 νƒ€μž…μ„ μ§€μ •ν•΄μ£ΌλŠ” 것이라고 보면 λœλ‹€.

μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜

μœ„μ—μ„œ λ³΄λ‹€μ‹œν”Ό, μ œλ„€λ¦­μ€ <> κΊΎμ‡  κ΄„ν˜Έ ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ”λ° 이λ₯Ό λ‹€μ΄μ•„λͺ¬λ“œ μ—°μ‚°μžλΌκ³  ν•œλ‹€. 그리고 이 κΊΎμ‡  κ΄„ν˜Έ μ•ˆμ— μ‹λ³„μž 기호λ₯Ό μ§€μ •ν•¨μœΌλ‘œμ¨ νŒŒλΌλ―Έν„°ν™” ν•  수 μžˆλ‹€. 이것을 마치 λ©”μ†Œλ“œκ°€ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ μ‚¬μš©ν•˜λŠ” 것과 λΉ„μŠ·ν•˜μ—¬ μ œλ„€λ¦­μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜(parameter) / νƒ€μž… λ³€μˆ˜ λΌκ³  λΆ€λ₯Έλ‹€.

java-Generics

 

νƒ€μž… νŒŒλΌλ―Έν„° μ •μ˜

이 νƒ€μž… λ§€κ°œλ³€μˆ˜λŠ” μ œλ„€λ¦­μ„ μ΄μš©ν•œ ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œλ₯Ό 섀계할 λ•Œ μ‚¬μš©λœλ‹€.

예λ₯Όλ“€μ–΄ λ‹€μŒ μ½”λ“œλŠ” μ œλ„€λ¦­μ„ κ°λ―Έν•œ 클래슀λ₯Ό μ •μ˜ν•œ μ½”λ“œμ΄λ‹€. 클래슀λͺ… μ˜†μ— <T> 기호둜 μ œλ„€λ¦­μ„ λΆ™μ—¬μ€€ κ±Έ λ³Ό 수 μžˆλ‹€. 그리고 클래슀 λ‚΄λΆ€μ—μ„œ μ‹λ³„μž 기호 T λ₯Ό 클래슀 ν•„λ“œμ™€, λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μœΌλ‘œ μ§€μ •λ˜μ–΄ μžˆλ‹€.

class FruitBox<T> {
    List<T> fruits = new ArrayList<>();

    public void add(T fruit) {
        fruits.add(fruit);
    }
}

μ œλ„€λ¦­ 클래슀λ₯Ό λ§Œλ“€μ—ˆμœΌλ©΄ 이λ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν•΄λ³΄μž. 마치 νŒŒλΌλ―Έν„°λ₯Ό μ§€μ •ν•΄μ„œ λ³΄λ‚΄λŠ” 것 처럼 생성 μ½”λ“œμ—μ„œ κΊΎμ‡  κ΄„ν˜Έ μ•ˆμ— 지정해주고 싢은 νƒ€μž…λͺ…을 ν• λ‹Ήν•΄μ£Όλ©΄, μ œλ„€λ¦­ 클래슀 μ„ μ–Έλ¬Έ λΆ€λΆ„μœΌλ‘œ κ°€μ„œ νƒ€μž… νŒŒλΌλ―Έν„° T κ°€ μ§€μ •λœ νƒ€μž…μœΌλ‘œ λͺ¨λ‘ λ³€ν™˜λ˜μ–΄ 클래슀의 νƒ€μž…μ΄ μ§€μ •λ˜κ²Œ λ˜λŠ” 것이닀.

// μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜μ— μ •μˆ˜ νƒ€μž…μ„ ν• λ‹Ή
FruitBox<Integer> intBox = new FruitBox<>(); 

// μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜μ— μ‹€μˆ˜ νƒ€μž…μ„ ν• λ‹Ή
FruitBox<Double> intBox = new FruitBox<>(); 

// μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜μ— λ¬Έμžμ—΄ νƒ€μž…μ„ ν• λ‹Ή
FruitBox<String> intBox = new FruitBox<>(); 

// ν΄λž˜μŠ€λ„ 넣어쀄 수 μžˆλ‹€. (Apple ν΄λž˜μŠ€κ°€ μžˆλ‹€κ³  κ°€μ •)
FruitBox<Apple> intBox = new FruitBox<Apple>();

이λ₯Ό 그림으둜 ν‘œν˜„ν•΄λ³΄λ©΄, λ‹€μŒκ³Ό 같이 μ œλ„€λ¦­ νƒ€μž… μ „νŒŒκ°€ 행해진고 보면 λœλ‹€. <T> λΆ€λΆ„μ—μ„œ μ‹€ν–‰λΆ€μ—μ„œ νƒ€μž…μ„ 받아와 λ‚΄λΆ€μ—μ„œ T νƒ€μž…μœΌλ‘œ μ§€μ •ν•œ λ©€λ²„λ“€μ—κ²Œ μ „νŒŒν•˜μ—¬ νƒ€μž…μ΄ ꡬ체적으둜 μ„€μ • λ˜λŠ” 것이닀. 이λ₯Ό μ „λ¬Έ μš©μ–΄λ‘œ ꡬ체화(Specialization) 라고 ν•œλ‹€.

java-Generics

 

νƒ€μž… νŒŒλΌλ―Έν„° μƒλž΅

μ œλ„€λ¦­ 객체λ₯Ό μ‚¬μš©ν•˜λŠ” 문법 ν˜•νƒœλ₯Ό 보면 μ–‘μͺ½ λ‘ ꡰ데에 κΊΎμ‡  κ΄„ν˜Έ μ œλ„€λ¦­ νƒ€μž…μ„ 지정함을 λ³Ό 수 μžˆλ‹€. ν•˜μ§€λ§Œ 맨 μ•žμ—μ„œ 클래슀λͺ…κ³Ό ν•¨κ»˜ νƒ€μž…μ„ 지정해 μ£Όμ—ˆλŠ”λ° ꡳ이 μƒμ„±μžκΉŒμ§€ μ œλ„€λ¦­μ„ 지정해 쀄 ν•„μš”κ°€ μ—†λ‹€. (쀑볡)

λ”°λΌμ„œ jdk 1.7 버전 이후뢀터,  new μƒμ„±μž λΆ€λΆ„μ˜ μ œλ„€λ¦­ νƒ€μž…μ„ μƒλž΅ν•  수 있게 λ˜μ—ˆλ‹€. μ œλ„€λ¦­ λ‚˜λ¦„λŒ€λ‘œ νƒ€μž… 좔둠을 ν•΄μ„œ μƒλž΅ 된 곳을 λ„£μ–΄μ£ΌκΈ° λ•Œλ¬Έμ— λ¬Έμ œκ°€ μ—†λŠ” 것이닀.

FruitBox<Apple> intBox = new FruitBox<Apple>();

// λ‹€μŒκ³Ό 같이 new μƒμ„±μž λΆ€λΆ„μ˜ μ œλ„€λ¦­μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜λŠ” μƒλž΅ν•  수 μžˆλ‹€.
FruitBox<Apple> intBox = new FruitBox<>();

 

νƒ€μž… νŒŒλΌλ―Έν„° ν• λ‹Ή κ°€λŠ₯ νƒ€μž…

μ œλ„€λ¦­μ—μ„œ ν• λ‹Ή 받을 수 μžˆλŠ” νƒ€μž…μ€ Reference νƒ€μž… 뿐이닀. 즉, intν˜• μ΄λ‚˜ doubleν˜• 같은 μžλ°” μ›μ‹œ νƒ€μž…(Primitive Type)을 μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ λ„˜κΈΈ 수 μ—†λ‹€λŠ” 말이닀.

μš°λ¦¬κ°€ Wrapper ν΄λž˜μŠ€μ— λŒ€ν•΄ κ³΅λΆ€ν• λ•Œ intν˜•, doubleν˜•μ΄ 이미 μ‘΄μž¬ν•˜λŠ”λ°, μ™œ ꡳ이 λ˜‘κ°™μ€ 역할을 ν•˜λŠ” Integerν˜•, Doubleν˜• 클래슀λ₯Ό λ§Œλ“€μ–΄λ†¨μ„κΉŒ 고민을 해본적이 μžˆμ—ˆμ„ 것이닀. λ°”λ‘œ μ΄λ•Œ μ‚¬μš©ν•˜λŠ” 것이라고 μ΄ν•΄ν•˜λ©΄ λœλ‹€.

λ°”λ‘œ 적응이 λ˜μ§€λŠ” μ•Šκ² μ§€λ§Œ, 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” λͺ¨λ“  것이 객체둜 ν†΅μ‹ ν•˜κΈ° λ•Œλ¬Έμ— λ²ˆκ±°λ‘­λ”λΌλ„ μ΅μˆ™ν•΄ 지어야 ν•œλ‹€.

// κΈ°λ³Έ νƒ€μž… intλŠ” μ‚¬μš© λΆˆκ°€ !!!
List<int> intList = new List<>(); 

// Wrapper 클래슀둜 λ„˜κ²¨μ£Όμ–΄μ•Ό ν•œλ‹€. (λ‚΄λΆ€μ—μ„œ μžλ™μœΌλ‘œ μ–Έλ°•μ‹±λ˜μ–΄ μ›μ‹œ νƒ€μž…μœΌλ‘œ 이용됨)
List<Integer> integerList = new List<>();

 

λ˜ν•œ μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°μ— ν΄λž˜μŠ€κ°€ νƒ€μž…μœΌλ‘œ μ˜¨λ‹€λŠ” 것은, 클래슀끼리 상속을 톡해 관계λ₯Ό λ§ΊλŠ” 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ λ‹€ν˜•μ„± 원리가 κ·ΈλŒ€λ‘œ 적용이 λœλ‹€λŠ” μ†Œλ¦¬μ΄λ‹€.

μ•„λž˜ 예제 μ½”λ“œλ₯Ό 보면 νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ <Fruit> 둜 μ§€μ •ν–ˆμ§€λ§Œ μ—…μΊμŠ€νŒ…μ„ 톡해 κ·Έ μžμ‹ 객체도 할당이 됨을 λ³Ό 수 μžˆλ‹€.

java-Generics

class Fruit { }
class Apple extends Fruit { }
class Banana extends Fruit { }

class FruitBox<T> {
    List<T> fruits = new ArrayList<>();

    public void add(T fruit) {
        fruits.add(fruit);
    }
}

public class Main {
    public static void main(String[] args) {
        FruitBox<Fruit> box = new FruitBox<>();
        
        // μ œλ„€λ¦­ νƒ€μž…μ€ λ‹€ν˜•μ„± 원리가 κ·ΈλŒ€λ‘œ μ μš©λœλ‹€.
        box.add(new Fruit());
        box.add(new Apple());
        box.add(new Banana());
    }
}

 

볡수 νƒ€μž… νŒŒλΌλ―Έν„°

μ œλ„€λ¦­μ€ λ°˜λ“œμ‹œ ν•œκ°œλ§Œ μ‚¬μš©ν•˜λΌλŠ” 법은 μ—†λ‹€. 만일 νƒ€μž… 지정이 μ—¬λŸ¬κ°œκ°€ ν•„μš”ν•  경우 2개, 3개 μ–Όλ§ˆλ“ μ§€ λ§Œλ“€ 수 μžˆλ‹€.

μ œλ„€λ¦­ νƒ€μž…μ˜ ꡬ뢄은 κΊ½μ‡  κ΄„ν˜Έ μ•ˆμ—μ„œ μ‰½ν‘œ(,)둜 ν•˜λ©° <T, U> 와 같은 ν˜•μ‹μ„ 톡해 볡수 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό 지정할 수 μžˆλ‹€. 그리고 λ‹Ήμ—°νžˆ 클래슀 μ΄ˆκΈ°ν™”ν• λ•Œ μ œλ„€λ¦­ νƒ€μž…μ„ λ‘κ°œλ₯Ό λ„˜κ²¨μ£Όμ–΄μ•Ό ν•œλ‹€.

import java.util.ArrayList;
import java.util.List;

class Apple {}
class Banana {}

class FruitBox<T, U> {
    List<T> apples = new ArrayList<>();
    List<U> bananas = new ArrayList<>();

    public void add(T apple, U banana) {
        apples.add(apple);
        bananas.add(banana);
    }
}

public class Main {
    public static void main(String[] args) {
    	// 볡수 μ œλ„€λ¦­ νƒ€μž…
        FruitBox<Apple, Banana> box = new FruitBox<>();
        box.add(new Apple(), new Banana());
        box.add(new Apple(), new Banana());
    }
}

 

쀑첩 νƒ€μž… νŒŒλΌλ―Έν„°

μ œλ„€λ¦­ 객체λ₯Ό μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ λ°›λŠ” ν˜•μ‹λ„ ν‘œν˜„ν•  수 μžˆλ‹€.

ArrayList μžμ²΄λ„ ν•˜λ‚˜μ˜ νƒ€μž…μœΌλ‘œμ¨ μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ 될수 있기 λ•Œλ¬Έμ— μ΄λ ‡κ²Œ 쀑첩 ν˜•μ‹μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” 것이닀.

public static void main(String[] args) {
    // LinkedList<String>을 μ›μ†Œλ‘œμ„œ μ €μž₯ν•˜λŠ” ArrayList
    ArrayList<LinkedList<String>> list = new ArrayList<LinkedList<String>>();

    LinkedList<String> node1 = new LinkedList<>();
    node1.add("aa");
    node1.add("bb");

    LinkedList<String> node2 = new LinkedList<>();
    node2.add("11");
    node2.add("22");

    list.add(node1);
    list.add(node2);
    System.out.println(list);
}

java-Generics

 

νƒ€μž… νŒŒλΌλ―Έν„° 기호 넀이밍

μ§€κΈˆκΉŒμ§€ μ œλ„€λ¦­ 기호λ₯Ό <T> 와 같이 μ¨μ„œ ν‘œν˜„ν–ˆμ§€λ§Œ μ‚¬μ‹€ μ‹λ³„μž κΈ°ν˜ΈλŠ” λ¬Έλ²•μ μœΌλ‘œ 정해진 것이 μ—†λ‹€.

λ‹€λ§Œ μš°λ¦¬κ°€ for문을 μ΄μš©ν• λ•Œ 루프 λ³€μˆ˜λ₯Ό i λ‘œ μ§€μ •ν•΄μ„œ μ‚¬μš©ν•˜λ“―μ΄, μ œλ„€λ¦­μ˜ ν‘œν˜„ λ³€μˆ˜λ₯Ό T λ‘œ ν‘œν˜„ν•œλ‹€κ³  보면 λœλ‹€. 만일 λ‘λ²ˆμ§Έ, μ„Έλ²ˆμ§Έ μ œλ„€λ¦­μ΄ ν•„μš”ν•˜λ‹€κ³  보면 for문의 jλ‚˜ k κ°™μ΄ S, U 둜 μ΄μ–΄λ‚˜κ°„λ‹€.

λͺ…λͺ…ν•˜κ³  μ‹Άμ€λŒ€λ‘œ 아무 λ‹¨μ–΄λ‚˜ 넣어도 λ¬Έμ œλŠ” μ—†μ§€λ§Œ, λŒ€μ€‘μ μœΌλ‘œ ν†΅ν•˜λŠ” 톡상적인 넀이밍이 있으면 개발이 μš©μ΄ν•΄ 지기 λ•Œλ¬Έμ— μ•„λž˜ ν‘œν™” 같은 암묡적인 κ·œμΉ™(convention)이 μ‘΄μž¬ν•œλ‹€. 예λ₯Όλ“€μ–΄ μ˜ˆμ œμ—μ„œ μ‚¬μš©λœ T λ₯Ό νƒ€μž… λ³€μˆ˜(type variable)라고 ν•˜λ©°, μž„μ˜μ˜ μ°Έμ‘°ν˜• νƒ€μž…μ„ μ˜λ―Έν•œλ‹€.

νƒ€μž… μ„€λͺ…
<T> νƒ€μž…(Type)
<E> μš”μ†Œ(Element), 예λ₯Ό λ“€μ–΄ List
<K> ν‚€(Key), 예λ₯Ό λ“€μ–΄ Map<k, v>
<V> 리턴 κ°’ λ˜λŠ” λ§€ν•‘λœ κ°’(Variable)
<N> 숫자(Number)
<S, U, V> 2번째, 3번째, 4λ²ˆμ§Έμ— μ„ μ–Έλœ νƒ€μž…

μ œλ„€λ¦­ μ‚¬μš© μ΄μœ μ™€ 이점

 

1. 컴파일 νƒ€μž„μ— νƒ€μž… 검사λ₯Ό 톡해 μ˜ˆμ™Έ 방지

μžλ°”μ—μ„œ μ œλ„€λ¦­(Generic)은 μžλ°” 1.5에 μΆ”κ°€λœ μŠ€νŽ™μ΄λ‹€. κ·Έλž˜μ„œ JDK 1.5 μ΄μ „μ—μ„œλŠ” μ—¬λŸ¬ νƒ€μž…μ„ 닀루기 μœ„ν•΄ μΈμˆ˜λ‚˜ λ°˜ν™˜κ°’μœΌλ‘œ Object νƒ€μž…μ„ μ‚¬μš©ν–ˆμ—ˆμ—ˆλ‹€. ν•˜μ§€λ§Œ Object둜 νƒ€μž…μ„ μ„ μ–Έν•  경우 λ°˜ν™˜λœ Object 객체λ₯Ό λ‹€μ‹œ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ 일일히 νƒ€μž… λ³€ν™˜μ„ ν•΄μ•Ό ν•˜λ©°, λŸ°νƒ€μž„ μ—λŸ¬κ°€ λ°œμƒν•  κ°€λŠ₯성도 μ‘΄μž¬ν•˜κ²Œ λœλ‹€.

μ•„λž˜ μ˜ˆμ œμ—μ„  Object νƒ€μž…μœΌλ‘œ μ„ μ–Έν•œ 배열에 Apple κ³Ό Banana 객체 νƒ€μž…μ„ μ €μž₯ν•˜κ³  이λ₯Ό λ‹€μ‹œ κ°€μ Έμ˜€λŠ” μ˜ˆμ œμ΄λ‹€.

class Apple {}
class Banana {}

class FruitBox {
    // λͺ¨λ“  클래슀 νƒ€μž…μ„ λ°›κΈ° μœ„ν•΄ 졜고 쑰상인 Object νƒ€μž…μœΌλ‘œ μ„€μ •
    private Object[] fruit;

    public FruitBox(Object[] fruit) {
        this.fruit = fruit;
    }

    public Object getFruit(int index) {
        return fruit[index];
    }
}
public static void main(String[] args) {
    Apple[] arr = {
            new Apple(),
            new Apple()
    };
    FruitBox box = new FruitBox(arr);

    Apple apple = (Apple) box.getFruit(0);
    Banana banana = (Banana) box.getFruit(1);
}

java-Generics

그런데 싀행해보면 μœ„μ™€ 같이 ClassCastException λŸ°νƒ€μž„ μ—λŸ¬κ°€ λ°œμƒν•˜κ²Œ λœλ‹€. 객체λ₯Ό κ°€μ Έμ˜¬λ•Œ ν˜•λ³€ν™˜λ„ 잘 ν•΄μ£Όμ–΄ λ¬Έμ œκ°€ μ—†λŠ” 것 같은데 무엇이 문제일까?

원인은 κ°„λ‹¨ν•˜λ‹€. Apple 객체 νƒ€μž…μ˜ 배열을 FruitBox에 λ„£μ—ˆλŠ”λ°, κ°œλ°œμžκ°€ μ°©κ°ν•˜κ³  Bananaλ₯Ό ν˜•λ³€ν™˜ν•˜μ—¬ κ°€μ Έμ˜€λ €κ³  ν•˜μ˜€κΈ° λ•Œλ¬Έμ— 생긴 ν˜„μƒμ΄λ‹€. 미리 μ½”λ“œμ—μ„œ λΉ¨κ°„μ€„λ‘œ μ•Œλ €μ€¬μœΌλ©΄ μ’‹κ² μ§€λ§Œ λ³΄λ‹€μ‹œν”Ό κΉ¨λ—ν•˜λ‹€.

java-Generics

 

μ œλ„€λ¦­μ„ μ΄μš©ν•˜λ©΄ 이런 μ–΄μ²˜κ΅¬λ‹ˆ μ—†λŠ” μ‹€μˆ˜λ₯Ό 미연에 방지λ₯Ό ν• μˆ˜ μžˆλ‹€. μ™œλƒν•˜λ©΄ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κΈ°μ „ 컴파일 νƒ€μž„μ— 미리 μ—λŸ¬λ₯Ό μ°Ύμ•„ μ•Œλ €μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€.

class FruitBox<T> {
    private T[] fruit;

    public FruitBox(T[] fruit) {
        this.fruit = fruit;
    }

    public T getFruit(int index) {
        return fruit[index];
    }
}
public static void main(String[] args) {
    Apple[] arr = {
            new Apple(),
            new Apple()
    };
    FruitBox<Apple> box = new FruitBox<>(arr);

    Apple apple = (Apple) box.getFruit(0);
    Banana banana = (Banana) box.getFruit(1);
}

java-Generics

이 처럼 μ œλ„€λ¦­μ€ ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œλ₯Ό μ •μ˜ν• λ•Œ νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ 객체의 μ„œλΈŒ νƒ€μž…μ„ μ§€μ •ν•΄μ€ŒμœΌλ‘œμ¨, 잘λͺ»λœ νƒ€μž…μ΄ μ‚¬μš©λ  수 μžˆλŠ” 문제λ₯Ό 컴파일 κ³Όμ •μ—μ„œ μ œκ±°ν•˜μ—¬ κ°œλ°œμ„ μš©μ΄ν•˜κ²Œ ν•΄μ€€λ‹€.

 

2. λΆˆν•„μš”ν•œ μΊμŠ€νŒ…μ„ μ—†μ•  μ„±λŠ₯ ν–₯상

μœ„μ˜ 예제 μ½”λ“œμ—μ„œ Apple 배열을 FruitBox의 Object λ°°μ—΄ 객체에 λ„£κ³ , λ°°μ—΄ μš”μ†Œλ₯Ό κ°€μ Έμ˜¬λ•Œ λ°˜λ“œμ‹œ λ‹€μš΄ μΊμŠ€νŒ…(down casting)을 톡해 가져와야 ν–ˆλ‹€. μ΄λŠ” 곧 좔가적인 μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜λŠ” 것과 κ°™λ‹€.

Apple[] arr = { new Apple(), new Apple(), new Apple() };
FruitBox box = new FruitBox(arr);

// κ°€μ Έμ˜¨ νƒ€μž…μ΄ Object νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— 일일히 λ‹€μš΄μΊμŠ€νŒ…μ„ 해야함 - μ“Έλ°μ—†λŠ” μ„±λŠ₯ λ‚­λΉ„
Apple apple1 = (Apple) box.getFruit(0);
Apple apple2 = (Apple) box.getFruit(1);
Apple apple3 = (Apple) box.getFruit(2);

 

반면 μ œλ„€λ¦­μ€ 미리 νƒ€μž…μ„ 지정 & μ œν•œν•΄ 놓기 λ•Œλ¬Έμ— ν˜• λ³€ν™˜(Type Casting)의 λ²ˆκ±°λ‘œμ›€μ„ 쀄일 수 있으며, νƒ€μž… 겁사에 λ“€μ–΄κ°€λŠ” λ©”λͺ¨λ¦¬λ₯Ό 쀄일 수 있고 λ”λΆˆμ–΄ 가독성도 쒋아진닀.

// 미리 μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό 톡해 ν˜•(type)을 μ§€μ •ν•΄λ†“μ•˜κΈ° λ•Œλ¬Έμ— λ³„λ„μ˜ ν˜•λ³€ν™˜μ€ ν•„μš”μ—†λ‹€.
FruitBox<Apple> box = new FruitBox<>(arr);

Apple apple = box.getFruit(0);
Apple apple = box.getFruit(1);
Apple apple = box.getFruit(2);

μ œλ„€λ¦­ μ‚¬μš© μ£Όμ˜μ‚¬ν•­

 

1. μ œλ„€λ¦­ νƒ€μž…μ˜ κ°μ²΄λŠ” 생성이 λΆˆκ°€

μ œλ„€λ¦­ νƒ€μž… 자체둜 νƒ€μž…μ„ μ§€μ •ν•˜μ—¬ 객체λ₯Ό μƒμ„±ν•˜λŠ” 것은 λΆˆκ°€λŠ₯ ν•œλ‹€. 즉, new μ—°μ‚°μž 뒀에 μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ μ˜¬μˆ˜λŠ” μ—†λ‹€.

class Sample<T> {
    public void someMethod() {
        // Type parameter 'T' cannot be instantiated directly
        T t = new T();
    }
}

 

2. static 멀버에 μ œλ„€λ¦­ νƒ€μž…μ΄ 올수 μ—†μŒ

μ•„λž˜ 처럼 static λ³€μˆ˜μ˜ 데이터 νƒ€μž…μœΌλ‘œ μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ μ˜¬μˆ˜λŠ” μ—†λ‹€. μ™œλƒν•˜λ©΄ static λ©€λ²„λŠ” ν΄λž˜μŠ€κ°€ λ™μΌν•˜κ²Œ κ³΅μœ ν•˜λŠ” λ³€μˆ˜λ‘œμ„œ μ œλ„€λ¦­ 객체가 μƒμ„±λ˜κΈ°λ„ 전에 이미 자료 νƒ€μž…μ΄ μ •ν•΄μ Έ μžˆμ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 즉, 논리적인 였λ₯˜μΈ 것이닀.

class Student<T> {
    private String name;
    private int age = 0;

    // static λ©”μ„œλ“œμ˜ λ°˜ν™˜ νƒ€μž…μœΌλ‘œ μ‚¬μš© λΆˆκ°€
    public static T addAge(int n) {

    }
}

java-Generics

class Student<T> {
    private String name;
    private int age = 0;

    // static λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜ νƒ€μž…μœΌλ‘œ μ‚¬μš© λΆˆκ°€
    public static void addAge(T n) {

    }
}

java-Generics

 

3. μ œλ„€λ¦­μœΌλ‘œ λ°°μ—΄ μ„ μ–Έ 주의점

기본적으둜 μ œλ„€λ¦­ 클래슀 자체λ₯Ό λ°°μ—΄λ‘œ λ§Œλ“€ μˆ˜λŠ” μ—†λ‹€.

class Sample<T> { 
}

public class Main {
    public static void main(String[] args) {
        Sample<Integer>[] arr1 = new Sample<>[10];
    }
}

java-Generics

ν•˜μ§€λ§Œ μ œλ„€λ¦­ νƒ€μž…μ˜ λ°°μ—΄ 선언은 ν—ˆμš©λœλ‹€.

μœ„μ˜ 식과 차이점은 배열에 μ €μž₯ν•  Sample 객체의 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό Integer λ‘œ μ§€μ •ν•œλ‹€λŠ” λœ»μ΄λ‹€. 즉, new Sample<Integer>() μΈμŠ€ν„΄μŠ€λŠ” μ €μž₯이 κ°€λŠ₯ν•˜λ©°, new Sample<String>() μΈμŠ€ν„΄μŠ€λŠ” μ €μž₯이 λΆˆκ°€λŠ₯ν•˜λ‹€λŠ” μ†Œλ¦¬μ΄λ‹€.

class Sample<T> { 
}

public class Main {
    public static void main(String[] args) {
    	// new Sample<Integer>() μΈμŠ€ν„΄μŠ€λ§Œ μ €μž₯ν•˜λŠ” 배열을 λ‚˜νƒ€λƒ„
        Sample<Integer>[] arr2 = new Sample[10]; 
        
        // μ œλ„€λ¦­ νƒ€μž…μ„ μƒλž΅ν•΄λ„ μœ„μ—μ„œ 이미 μ •μ˜ν–ˆκΈ° λ•Œλ¬Έμ— Integer κ°€ μžλ™μœΌλ‘œ 좔둠됨
        arr2[0] = new Sample<Integer>(); 
        arr2[1] = new Sample<>();
        
        // ! Integerκ°€ μ•„λ‹Œ νƒ€μž…μ€ μ €μž₯ λΆˆκ°€λŠ₯
        arr2[2] = new Sample<String>();
    }
}

μ œλ„€λ¦­ 객체 λ§Œλ“€μ–΄λ³΄κΈ°

μ œλ„€λ¦­μ„ μ΄μš©ν•΄ 직접 ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€, λ©”μ„œλ“œλ₯Ό λ§Œλ“€μ–΄λ³΄κ³  μ‚¬μš©ν•΄λ³΄λŠ” μ‹œκ°„μ„ κ°€μ Έλ³΄μž.

 

μ œλ„€λ¦­ 클래슀

클래슀 μ„ μ–Έλ¬Έ μ˜†μ— μ œλ„€λ¦­ νƒ€μž… λ§€κ°œλ³€μˆ˜κ°€ 쓰이면, 이λ₯Ό μ œλ„€λ¦­ 클래슀라고 ν•œλ‹€.

class Sample<T> {
    private T value; // 멀버 λ³€μˆ˜ val의 νƒ€μž…μ€ T 이닀.

    // T νƒ€μž…μ˜ κ°’ val을 λ°˜ν™˜ν•œλ‹€.
    public T getValue() {
        return value;
    }

    // T νƒ€μž…μ˜ 값을 멀버 λ³€μˆ˜ val에 λŒ€μž…ν•œλ‹€.
    public void setValue(T value) {
        this.value = value;
    }
}
public static void main(String[] args) {
    // μ •μˆ˜ν˜•μ„ λ‹€λ£¨λŠ” μ œλ„€λ¦­ 클래슀
    Sample<Integer> s1 = new Sample<>();
    s1.setValue(1);

    // μ‹€μˆ˜ν˜•μ„ λ‹€λ£¨λŠ” μ œλ„€λ¦­ 클래슀
    Sample<Double> s2 = new Sample<>();
    s2.setValue(1.0);

    // λ¬Έμžμ—΄μ„ λ‹€λ£¨λŠ” μ œλ„€λ¦­ 클래슀
    Sample<String> s3 = new Sample<>();
    s3.setValue("1");
}

μ œλ„€λ¦­ μΈν„°νŽ˜μ΄μŠ€

μΈν„°νŽ˜μ΄μŠ€μ—λ„ μ œλ„€λ¦­μ„ 적용 ν•  수 μžˆλ‹€. 단, μΈν„°νŽ˜μ΄μŠ€λ₯Ό implements ν•œ ν΄λž˜μŠ€μ—μ„œλ„ μ˜€λ²„λΌμ΄λ”©ν•œ λ©”μ„œλ“œλ₯Ό μ œλ„€λ¦­ νƒ€μž…μ— λ§žμΆ°μ„œ λ˜‘κ°™μ΄ κ΅¬ν˜„ν•΄ μ£Όμ–΄μ•Ό ν•œλ‹€.

interface ISample<T> {
    public void addElement(T t, int index);
    public T getElement(int index);
}

class Sample<T> implements ISample<T> {
    private T[] array;

    public Sample() {
        array = (T[]) new Object[10];
    }

    @Override
    public void addElement(T element, int index) {
        array[index] = element;
    }

    @Override
    public T getElement(int index) {
        return array[index];
    }
}
public static void main(String[] args) {
    Sample<String> sample = new Sample<>();
    sample.addElement("This is string", 5);
    sample.getElement(5);
}

 

μ œλ„€λ¦­ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

특히 μ œλ„€λ¦­ μΈν„°νŽ˜μ΄μŠ€κ°€ 정말 많이 μ‚¬μš©λ˜λŠ” 곳이 λ°”λ‘œ λžŒλ‹€ ν‘œν˜„μ‹μ˜ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€. 아직 μžλ°”μ˜ λžŒλ‹€μ‹μ— λŒ€ν•΄ λ°°μš°μ§€ μ•Šμ€ λ…μžλΆ„λ“€λ„ κ³„μ‹œκ² μ§€λ§Œ, μ•žμœΌλ‘œ 배울 μ˜ˆμ •μΌ κ²ƒμ΄λ‹ˆ λžŒλ‹€ ν•¨μˆ˜μ™€ μ œλ„€λ¦­μ˜ μ‘μš© ν˜•νƒœλ₯Ό λˆˆμ— 읡히고 κ°€λŠ”κ²ƒμ„ μΆ”μ²œν•˜λŠ” λ°”λ‹€.

// μ œλ„€λ¦­μœΌλ‘œ νƒ€μž…μ„ λ°›μ•„, ν•΄λ‹Ή νƒ€μž…μ˜ 두 값을 λ”ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€
interface IAdd<T> {
    public T add(T x, T y);
}

public class Main {
    public static void main(String[] args) {
        // μ œλ„€λ¦­μ„ 톡해 λžŒλ‹€ ν•¨μˆ˜μ˜ νƒ€μž…μ„ κ²°μ •
        IAdd<Integer> o = (x, y) -> x + y; // λ§€κ°œλ³€μˆ˜ x와 y 그리고 λ°˜ν™˜ν˜• νƒ€μž…μ΄ intν˜•μœΌλ‘œ μ„€μ •λœλ‹€.
        
        int result = o.add(10, 20);
        System.out.println(result); // 30
    }
}

μ œλ„€λ¦­ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€


μ œλ„€λ¦­ λ©”μ„œλ“œ

μ œλ„€λ¦­ λ©”μ„œλ“œ 뢀뢄은 μ œλ„€λ¦­ 클래슀, μΈν„°νŽ˜μ΄μŠ€μ™€ 달리 λ‚œμ΄λ„κ°€ 쑰금 μžˆλ‹€.

μ•„λž˜μ™€ 같이 μ œλ„€λ¦­ ν΄λž˜μŠ€μ—μ„œ μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ‚¬μš©ν•˜λŠ” λ©”μ„œλ“œλ₯Ό μ œλ„€λ¦­ λ©”μ„œλ“œλΌκ³  μ°©κ°ν•˜κΈ° μ‰¬μš΄λ°, 이것은 κ·Έλƒ₯ νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ νƒ€μž…μ„ μ§€μ •ν•œ λ©”μ„œλ“œ 일 뿐이닀.

class FruitBox<T> {

    public T addBox(T x, T y) {
        // ...
    }
}

μ œλ„€λ¦­ λ©”μ„œλ“œλž€, λ©”μ„œλ“œμ˜ 선언뢀에 <T> κ°€ μ„ μ–Έλœ λ©”μ„œλ“œλ₯Ό λ§ν•œλ‹€.

μœ„μ—μ„œλŠ” 클래슀의 μ œλ„€λ¦­ <T> μ—μ„œ μ„€μ •λœ νƒ€μž…μ„ 받아와 λ°˜ν™˜ νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•  뿐인 일반 λ©”μ„œλ“œλΌλ©΄, μ œλ„€λ¦­ λ©”μ„œλ“œλŠ” 직접 λ©”μ„œλ“œμ— <T> μ œλ„€λ¦­μ„ μ„€μ •ν•¨μœΌλ‘œμ„œ λ™μ μœΌλ‘œ νƒ€μž…μ„ 받아와 μ‚¬μš©ν•  수 μžˆλŠ” λ…λ¦½μ μœΌλ‘œ 운용 κ°€λŠ₯ν•œ μ œλ„€λ¦­ λ©”μ„œλ“œλΌκ³  μ΄ν•΄ν•˜λ©΄ λœλ‹€.

class FruitBox<T> {
	
    // 클래슀의 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό 받아와 μ‚¬μš©ν•˜λŠ” 일반 λ©”μ„œλ“œ
    public T addBox(T x, T y) {
        // ...
    }
    
    // λ…λ¦½μ μœΌλ‘œ νƒ€μž… ν• λ‹Ή μš΄μ˜λ˜λŠ” μ œλ„€λ¦­ λ©”μ„œλ“œ
    public static <T> T addBoxStatic(T x, T y) {
        // ...
    }
}

즉, μ œλ„€λ¦­ ν΄λž˜μŠ€μ— μ •μ˜λœ νƒ€μž… λ§€κ°œλ³€μˆ˜μ™€ μ œλ„€λ¦­ λ©”μ„œλ“œμ— μ •μ˜λœ νƒ€μž… λ§€κ°œλ³€μˆ˜λŠ” λ³„κ°œμΈκ²Œ λ˜λŠ” 것이닀. μ œλ„€λ¦­ λ©”μ„œλ“œμ˜ μ œλ„€λ¦­ νƒ€μž… μ„ μ–Έ μœ„μΉ˜λŠ” λ©”μ„œλ“œ λ°˜ν™˜ νƒ€μž… λ°”λ‘œ μ•žμ΄λ‹€.

generic-method

 

μ œλ„€λ¦­ λ©”μ„œλ“œ 호좜 원리

그럼 μ œλ„€λ¦­ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœμ€ μ–΄λ–»κ²Œ ν• κΉŒ?

μ œλ„€λ¦­ νƒ€μž…μ„ λ©”μ„œλ“œλͺ… μ˜†μ— μ§€μ •ν•΄μ€¬μœΌλ‹ˆ, 호좜 μ—­μ‹œ λ©”μ„œλ“œ μ™Όμͺ½μ— μ œλ„€λ¦­ νƒ€μž…μ΄ μœ„μΉ˜ν•˜κ²Œ λœλ‹€.

FruitBox.<Integer>addBoxStatic(1, 2);
FruitBox.<String>addBoxStatic("μ•ˆλ…•", "μž˜κ°€");

generic-method

μ΄λ•Œ μ»΄νŒŒμΌλŸ¬κ°€ μ œλ„€λ¦­ νƒ€μž…μ— λ“€μ–΄κ°ˆ 데이터 νƒ€μž…μ„ λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 톡해 μΆ”μ •ν•  수 있기 λ•Œλ¬Έμ—, λŒ€λΆ€λΆ„μ˜ 경우 μ œλ„€λ¦­ λ©”μ„œλ“œμ˜ νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μƒλž΅ν•˜κ³  ν˜ΈμΆœν•  수 μžˆλ‹€. 

// λ©”μ„œλ“œμ˜ μ œλ„€λ¦­ νƒ€μž… μƒλž΅
FruitBox.addBoxStatic(1, 2); 
FruitBox.addBoxStatic("μ•ˆλ…•", "μž˜κ°€");

generic-method

 

그런데 ν•œκ°€μ§€ κΆκΈˆν•œ 점이 μžˆμ„ 것이닀. 클래슀 μ˜†μ— λΆ™μ–΄μžˆλŠ” μ œλ„€λ¦­κ³Ό μ œλ„€λ¦­ λ©”μ†Œλ“œλŠ” λ˜‘κ°™μ€ <T> 인데 μ–΄λ–»κ²Œ μ œλ„€λ¦­ λ©”μ„œλ“œλ§Œμ΄ λ…λ¦½μ μœΌλ‘œ μš΄μš©λ˜λŠ”μ§€ 말이닀.

사싀은 처음 μ œλ„€λ¦­ 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•˜λ©΄, 클래슀 νƒ€μž… λ§€κ°œλ³€μˆ˜μ— μ „λ‹¬ν•œ νƒ€μž…μ— 따라 μ œλ„€λ¦­ λ©”μ†Œλ“œλ„ νƒ€μž…μ΄ μ •ν•΄μ§€κ²Œ λœλ‹€. 그런데 만일 μ œλ„€λ¦­ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν• λ•Œ 직접 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό λ‹€λ₯΄κ²Œ μ§€μ •ν•΄μ£Όκ±°λ‚˜, λ‹€λ₯Έ νƒ€μž…μ˜ 데이터λ₯Ό λ§€κ°œλ³€μˆ˜μ— λ„˜κΈ΄ν•˜λ©΄ λ…립적인 νƒ€μž…μ„ 가진 μ œλ„€λ¦­ λ©”μ„œλ“œλ‘œ 운용되게 λœλ‹€.

class FruitBox<T, U> {
    // λ…λ¦½μ μœΌλ‘œμš΄μ˜λ˜λŠ” μ œλ„€λ¦­ λ©”μ„œλ“œ
    public <T, U> void printBox(T x, U y) {
        // ν•΄λ‹Ή λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž… 좜λ ₯
        System.out.println(x.getClass().getSimpleName());
        System.out.println(y.getClass().getSimpleName());
    }
}
public static void main(String[] args) {
    FruitBox<Integer, Long> box1 = new FruitBox<>();

    // μΈμŠ€ν„΄μŠ€ν™”μ— μ§€μ •λœ νƒ€μž… νŒŒλΌλ―Έν„° <Integer, Long>
    box1.printBox(1, 1);

    // ν•˜μ§€λ§Œ μ œλ„€λ¦­ λ©”μ„œλ“œμ— λ‹€λ₯Έ νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ§€μ •ν•˜λ©΄ λ…λ¦½μ μœΌλ‘œ 운용 λœλ‹€.
    box1.<String, Double>printBox("hello", 5.55);
    box1.printBox("hello", 5.55); // μƒλž΅ κ°€λŠ₯
}

generic-method
generic-method


μ œλ„€λ¦­ νƒ€μž… λ²”μœ„ ν•œμ •ν•˜κΈ°

μ œλ„€λ¦­μ— νƒ€μž…μ„ μ§€μ •ν•΄μ€ŒμœΌλ‘œμ„œ 클래슀의 νƒ€μž…μ„ 컴파일 νƒ€μž„μ—μ„œ μ •ν•˜μ—¬ νƒ€μž… μ˜ˆμ™Έμ— λŒ€ν•œ μ•ˆμ •μ„±μ„ ν™•λ³΄ν•˜λŠ” 것은 μ’‹μ§€λ§Œ λ¬Έμ œλŠ” λ„ˆλ¬΄ μžμœ λ‘­λ‹€λŠ” 점이닀.

예λ₯Όλ“€μ–΄ λ‹€μŒ 계산기 ν΄λž˜μŠ€κ°€ μžˆλ‹€κ³  ν•˜μž. μ •μˆ˜, μ‹€μˆ˜ ꡬ뢄없이 λͺ¨λ‘ 받을 수 있게 ν•˜κΈ°μœ„ν•΄ μ œλ„€λ¦­μœΌλ‘œ 클래슀λ₯Ό λ§Œλ“€μ–΄μ£Όμ—ˆλ‹€. ν•˜μ§€λ§Œ λ‹¨μˆœνžˆ <T> λ‘œ μ§€μ •ν•˜κ²Œ 되면 μˆ«μžμ— κ΄€λ ¨λœ 래퍼 클래슀 뿐만 μ•„λ‹ˆλΌ Stringμ΄λ‚˜ λ‹€λ₯Έ ν΄λž˜μŠ€λ“€λ„ λŒ€μž…μ΄ κ°€λŠ₯ν•˜λ‹€λŠ” 점이 λ¬Έμ œμ΄λ‹€.

// 숫자만 λ°›μ•„ κ³„μ‚°ν•˜λŠ” 계산기 클래슀 λͺ¨λ“ˆ
class Calculator<T> {
    void add(T a, T b) {}
    void min(T a, T b) {}
    void mul(T a, T b) {}
    void div(T a, T b) {}
}

public class Main {
    public static void main(String[] args) {
        // μ œλ„€λ¦­μ— 아무 νƒ€μž…μ΄λ‚˜ λͺ¨λ‘ 할당이 κ°€λŠ₯
        Calculator<Number> cal1 = new Calculator<>();
        Calculator<Object> cal2 = new Calculator<>();
        Calculator<String> cal3 = new Calculator<>();
        Calculator<Main> cal4 = new Calculator<>();
    }
}

개발자의 μ˜λ„λ‘œλŠ” 계산기 클래슀의 μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°λ‘œ Number μžλ£Œν˜•λ§Œ λ“€μ–΄μ˜€λ„λ‘ ν•˜κ³  λ¬Έμžμ—΄μ΄λ‚˜ 또 λ‹€λ₯Έ 클래슀 μžλ£Œν˜•μ΄ λ“€μ–΄μ˜€λ©΄ μ•ˆλ˜κ²Œ ν•˜κ³  μ‹Άλ‹€κ³  ν•œλ‹€. κ·Έλž˜μ„œ λ‚˜μ˜¨ 것이 μ œν•œλœ νƒ€μž… λ§€κ°œλ³€μˆ˜ (Bounded Type Parameter) 이닀.


νƒ€μž… ν•œμ • ν‚€μ›Œλ“œ extends

기본적인 μš©λ²•μ€ <T extends [μ œν•œνƒ€μž…]> μ΄λ‹€. μ œλ„€λ¦­ <T> μ— extends ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬μ€ŒμœΌλ‘œμ¨, <T extends Number> μ œλ„€λ¦­μ„ Number ν΄λž˜μŠ€μ™€ κ·Έ ν•˜μœ„ νƒ€μž…(Integer, Double)λ“€λ§Œ 받도둝 νƒ€μž… νŒŒλΌλ―Έν„° λ²”μœ„λ₯Ό μ œν•œ ν•œ 것이닀. 

클래슀의 상속 ν‚€μ›Œλ“œμ™€ μ œλ„€λ¦­μ˜ νƒ€μž… ν•œμ • ν‚€μ›Œλ“œκ°€ λ‘˜λ‹€ λ˜‘κ°™μ΄ extends 라 ν˜Όλ™ν•  μ†Œμ§€κ°€ 닀뢄이 μžˆλ‹€. κΊΎμ‡  κ΄„ν˜Έ μ•ˆμ— extendsκ°€ 있으면 이건 μ œν•œμ„ μ˜λ―Έν•˜λ©° κ΄„ν˜Έ λ°”κΉ₯에 있으면 μƒμ†μœΌλ‘œ 보면 λœλ‹€.

java-Generics
νƒ€μž…μ΄ Number μ΄ν•˜λ‘œ μ œν•œλ˜μ–΄ 빨간쀄이 뜨게 λœλ‹€

 

μΈν„°νŽ˜μ΄μŠ€ νƒ€μž… ν•œμ •

extends ν‚€μ›Œλ“œ λ‹€μŒμ— 올 νƒ€μž…μ€ 일반 클래슀, 좔상 클래슀, μΈν„°νŽ˜μ΄μŠ€ λͺ¨λ‘ 올 수 μžˆλ‹€. μΈν„°νŽ˜μ΄μŠ€ 뢀뢄은 μ•½κ°„ ν–‡κΉ”λ¦΄μˆ˜ μžˆλŠ”λ°, 클래슀의 상속 관계와 닀름이 μ—†μœΌλ‹ˆ κ·ΈλŒ€λ‘œ λΉ—λŒ€μ–΄ μ μš©ν•˜λ©΄ λœλ‹€.

interface Readable {
}

// μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 클래슀
public class Student implements Readable {
}
 
// μΈν„°νŽ˜μ΄μŠ€λ₯Ό Readableλ₯Ό κ΅¬ν˜„ν•œ 클래슀만 μ œλ„€λ¦­ κ°€λŠ₯
public class School <T extends Readable> {
}
public static void main(String[] args) {
    // νƒ€μž… νŒŒλΌλ―Έν„°μ— μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀만이 올수 있게 됨	
    School<Student> a = new School<Student>();
}

 

닀쀑 νƒ€μž… ν•œμ •

만일 2개 μ΄μƒμ˜ νƒ€μž…μ„ λ™μ‹œμ— 상속(κ΅¬ν˜„)ν•œ 경우둜 νƒ€μž… μ œν•œν•˜κ³  μ‹Άλ‹€λ©΄,  & μ—°μ‚°μžλ₯Ό μ΄μš©ν•˜λ©΄ λœλ‹€. ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€λ“€μ„ λ™μ‹œμ— κ΅¬ν˜„ν•œ ν΄λž˜μŠ€κ°€ μ œλ„€λ¦­ νƒ€μž…μ˜ λŒ€μƒμ΄ 되게 λœλ‹€.

단, μžλ°”μ—μ„œλŠ” 닀쀑 상속을 μ§€μ›ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— ν΄λž˜μŠ€λ‘œλŠ” 닀쀑 extendsλŠ” λΆˆκ°€λŠ₯ν•˜κ³  μ˜€λ‘œμ§€ μΈν„°νŽ˜μ΄μŠ€λ‘œλ§Œμ΄ κ°€λŠ₯ν•˜λ‹€.

interface Readable {}
interface Closeable {}

class BoxType implements Readable, Closeable {}

class Box<T extends Readable & Closeable> {
    List<T> list = new ArrayList<>();

    public void add(T item) {
        list.add(item);
    }
}
public static void main(String[] args) {
    // Readable 와 Closeable λ₯Ό λ™μ‹œμ— κ΅¬ν˜„ν•œ 클래슀만이 νƒ€μž… 할당이 κ°€λŠ₯ν•˜λ‹€
    Box<BoxType> box = new Box<>();

    // 심지어 μ΅œμƒμœ„ Object ν΄λž˜μŠ€μ—¬λ„ ν• λ‹Ή λΆˆκ°€λŠ₯ν•˜λ‹€
    Box<Object> box2 = new Box<>(); // ! Error
}

 

μ œλ„€λ¦­μ΄ μ—¬λŸ¬κ°œμΈ 닀쀑 νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό μ‚¬μš©ν•  κ²½μš°μ—λ„ 각각 닀쀑 μ œν•œμ„ κ±°λŠ” 것도 κ°€λŠ₯ν•˜λ‹€. (가독성이 μœΌμ•…μ΄ λ˜λŠ”κ±΄ 함정)

interface Readable {}
interface Closeable {}
interface Appendable {}
interface Flushable {}

class School<T extends Readable & Closeable, U extends Appendable & Closeable & Flushable> 
    void func(T reader, U writer){
    }
}

 

μž¬κ·€μ  νƒ€μž… ν•œμ •

μž¬κ·€μ  νƒ€μž… ν•œμ •μ΄λž€ 자기 μžμ‹ μ΄ λ“€μ–΄κ°„ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•˜μ—¬ νƒ€μž… λ§€κ°œλ³€μˆ˜μ˜ ν—ˆμš© λ²”μœ„λ₯Ό ν•œμ • μ‹œν‚€λŠ” 것을 λ§ν•œλ‹€. 싀무에선 주둜 Comparable μΈν„°νŽ˜μ΄μŠ€μ™€ ν•¨κ»˜ 쓰인닀.

예λ₯Όλ“€μ–΄ λ‹€μŒκ³Ό 같이 <E extends Comparable<E>> μ œλ„€λ¦­ E의 νƒ€μž… λ²”μœ„λ₯Ό Comparable<E> 둜 ν•œμ •ν•œλ‹€λŠ” Eλ₯Ό μ€‘μ²©μ‹œν‚¨ ν‘œν˜„μ‹μ„ μ‚¬μš©ν• μˆ˜ μžˆλŠ”λ°, 이 말은 'νƒ€μž… EλŠ” 자기 μžμ‹ μ„ μ„œλΈŒ νƒ€μž…μœΌλ‘œ κ΅¬ν˜„ν•œ Comparable κ΅¬ν˜„μ²΄λ‘œ ν•œμ •' ν•œλ‹€λŠ” λœ»μ΄λ‹€.

ComparableλŠ” 객체끼리 비ꡐλ₯Ό ν•΄μ•Ό ν• λ•Œ compareTo() λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”©ν• λ•Œ κ΅¬ν˜„ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.
μžλ°”μ—μ„œ Integer, Double, String 등이 κ°’ 비ꡐ가 λ˜λŠ” μ΄μœ κ°€ 기본적으둜 Comparableλ₯Ό κ΅¬ν˜„ν•˜κ³  있기 λ•Œλ¬Έμ΄λ‹€.

즉, Integer 객체λ₯Ό μ œλ„€λ¦­ νƒ€μž… E에 ν• λ‹Ήν•˜κ²Œ λœλ‹€λ©΄, Comparable을 κ΅¬ν˜„ν•œ κ°μ²΄λ©΄μ„œ μ˜€λ‘œμ§€ 같은 E인 Integer νƒ€μž…λ§Œ λ°›λŠ”λ‹€λŠ” μ˜λ―Έκ°€ λœλ‹€. (자기 μžμ‹ λ§Œ λ°›λŠ” λ‹€λŠ” ν‘œν˜„μ„ μ–΄λ ΅κ²Œ λΉ™λŒλ € ν‘œν˜„ν•œ 것이닀)

λ‹€μŒμ€ μ»¬λ ‰μ…˜μ„ 인자둜 λ°›μ•„ μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ“€μ„ μ΅œλŒ€κ°’(max)λ₯Ό ꡬ해 λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œ μ˜ˆμ œμ΄λ‹€. μ œλ„€λ¦­ λ©”μ„œλ“œ νƒ€μž…μœΌλ‘œ μž¬κ·€μ  νƒ€μž… ν•œμ •μ΄ μ‚¬μš©λ˜μ—ˆλ‹€.

class Compare {
	// μ™ΈλΆ€λ‘œ λ“€μ–΄μ˜¨ νƒ€μž… EλŠ” Comparable<E>λ₯Ό κ΅¬ν˜„ν•œ E 객체 이어야 ν•œλ‹€.
    public static <E extends Comparable<E>> E max(Collection<E> collection) {
        if(collection.isEmpty()) throw new IllegalArgumentException("μ»¬λ ‰μ…˜μ΄ λΉ„μ–΄ μžˆμŠ΅λ‹ˆλ‹€.");

        E result = null;
        for(E e: collection) {
            if(result == null) {
                result = e;
                continue;
            }

            if(e.compareTo(result) > 0) {
                result = e;
            }
        }

        return result;
    }
}
public static void main(String[] args) {
    Collection<Integer> list = Arrays.asList(56, 34, 12, 31, 65, 77, 91, 88);
    System.out.println(Compare.max(list)); // 91
    
    Collection<Number> list2 = Arrays.asList(56, 34, 12, 31, 65, 77, 91, 88);
    System.out.println(Compare.max(list2)); // ! Error - Number 좔상 λ©”μ„œλ“œλŠ” Comparableλ₯Ό κ΅¬ν˜„ν•˜μ§€μ•Šμ•˜κΈ° λ•Œλ¬Έμ— λΆˆκ°€λŠ₯
}

μ œλ„€λ¦­ ν˜•λ³€ν™˜

 

μ œλ„€λ¦­ μΊμŠ€νŒ… 문제

λ°°μ—΄κ³Ό 같은 일반적인 λ³€μˆ˜ νƒ€μž…κ³Ό 달리 μ§€λ„€λ¦­ μ„œλΈŒ νƒ€μž…κ°„μ—λŠ” ν˜•λ³€ν™˜μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€. 심지어 λŒ€μž…λœ νƒ€μž…μ΄ Object일지라도 말이닀. μžμ—°μŠ€λŸ½κ²Œ λ‹€ν˜•μ„±μ΄ 적용될 것이라 μƒκ°ν•˜μ˜€μ§€λ§Œ, 싀상 μ œλ„€λ¦­μ€ 전달받은 λ”± κ·Έ νƒ€μž…μœΌλ‘œλ§Œ μ„œλ‘œ μΊμŠ€νŒ…μ΄ κ°€λŠ₯ν•œ 것이닀.

μ²˜μŒμ— μ†Œκ°œν•œ νƒ€μž… νŒŒλΌλ―Έν„°μ˜ λ‹€ν˜•μ„±μ€ 포함 μ›μ†Œλ‘œμ„œ κ°€λŠ₯ν•˜λ‹€λŠ”κ±°μ§€, ν˜•λ³€ν™˜μ€ 객체 λŒ€ 객체λ₯Ό λ§ν•˜λŠ” κ±°λ‹ˆ λ‹€λ₯Έ κ°œλ…μ΄λ‹€.

// 배열은 OK 
Object[] arr = new Integer[1];

// μ œλ„€λ¦­μ€ ERROR 
List<Object> list = new ArrayList<Integer>();
List<Object> listObj = null; 
List<String> listStr = null; 

// μ—λŸ¬. List<String> -> List<Object>
listObj = (List<String>) listStr;

// μ—λŸ¬. List<Object> -> List<String>
listStr = (List<Object>) listObj;

 

이 νŠΉμ§•μ΄ μ™œ λ¬Έμ œμ‹œκ°€ λ˜λƒλ©΄μ€ μ œλ„€λ¦­ 객체에 μš”μ†Œλ₯Ό λ„£κ±°λ‚˜ κ°€μ Έμ˜¬λ•Œ, μΊμŠ€νŒ… 문제둜 인해 μ• λ‘œμ‚¬ν•­μ΄ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

예λ₯Ό λ“€μ–΄ λ°°μ—΄ 같은 경우 반볡문의 λ³€μˆ˜λ‘œ Object νƒ€μž…μœΌλ‘œ λ°›μ•„ μ‚¬μš©ν•΄λ„ λ¬Έμ œκ°€ μ—†λ‹€.

public static void main(String[] args) {
    Apple[] integers = new Apple[]{
            new Apple(),
            new Apple(),
            new Apple(),
    };
    print(integers);
}

public static void print(Fruit[] arr) {
    for (Object e : arr) {
        System.out.println(e);
    }
}

ν•˜μ§€λ§Œ μœ„μ˜ μ½”λ“œμ—μ„œ 배열을 리슀트의 μ œλ„€λ¦­μœΌλ‘œ λ°”κΎΈλ©΄ 컴파일 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

public static void main(String[] args) {
    List<Integer> lists = new ArrayList<>(Arrays.asList(1, 2, 3));
    print(lists); // ! 컴파일 μ—λŸ¬ λ°œμƒ
}

public static void print(List<Object> list) {
    for (Object e : list) {
        System.out.println(e);
    }
}

λ°°μ—΄ 같은 경우 print λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ•„κ·œλ¨ΌνŠΈκ°€ λ„˜μ–΄κ°ˆλ•Œ Integer[] λ°°μ—΄ νƒ€μž…μ΄ Object[] λ°°μ—΄ νƒ€μž…μœΌλ‘œ μ—…μΊμŠ€νŒ…μ΄ μ μš©λ˜μ–΄ λ¬Έμ œκ°€ μ—†μ§€λ§Œ, μ œλ„€λ¦­ 같은 경우 νƒ€μž… νŒŒλΌλ―Έν„°κ°€ μ˜€λ‘œμ§€ λ˜‘κ°™μ€ νƒ€μž…λ§Œ λ°›κΈ° λ•Œλ¬Έμ— λ‹€ν˜•μ„±μ„ μ΄μš©ν• μˆ˜ μ—†μ–΄μ„œ 그런 것이닀.


μ œλ„€λ¦­ μ™€μΌλ“œ μΉ΄λ“œ

λ”°λΌμ„œ μ œλ„€λ¦­ κ°„μ˜ ν˜•λ³€ν™˜μ„ μ„±λ¦½λ˜κ²Œ ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ œλ„€λ¦­μ—μ„œ μ œκ³΅ν•˜λŠ” μ™€μΌλ“œ μΉ΄λ“œ ?  λ¬Έλ²•μ„ μ΄μš©ν•˜μ—¬μ•Ό ν•œλ‹€. 

  • <?> : Unbounded Wildcards (μ œν•œ μ—†μŒ)
    • νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό λŒ€μΉ˜ν•˜λŠ” ꡬ체적인 νƒ€μž…μœΌλ‘œ λͺ¨λ“  ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ΄ 올 수 μžˆλ‹€
  • <? extends μƒμœ„νƒ€μž…> : Upper Bounded Wildcards (μƒμœ„ 클래슀 μ œν•œ)
    • νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό λŒ€μΉ˜ν•˜λŠ” ꡬ체적인 νƒ€μž…μœΌλ‘œ μƒμœ„ νƒ€μž…μ΄λ‚˜ μƒμœ„ νƒ€μž…μ˜ ν•˜μœ„ νƒ€μž…λ§Œ 올 수 μžˆλ‹€
  • <? super ν•˜μœ„νƒ€μž…> : Lower Bounded Wildcards (ν•˜μœ„ 클래슀 μ œν•œ)
    • νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό λŒ€μΉ˜ν•˜λŠ” ꡬ체적인 νƒ€μž…μœΌλ‘œ ν•˜μœ„ νƒ€μž…μ΄λ‚˜ ν•˜μœ„ νƒ€μž…μ˜ μƒμœ„ νƒ€μž…λ§Œ 올 수 μžˆλ‹€
List<? extends Object> list = new ArrayList<String>();

List<? super String> list2 = new ArrayList<Object>();
public static void main(String[] args) {
    List<Integer> lists = new ArrayList<>(Arrays.asList(1, 2, 3));
    print(lists); // OK
}

// Number와 κ·Έ ν•˜μœ„ νƒ€μž…(Integer, Double λ“±) λ§Œμ„ λ°›λŠ”λ‹€
public static void print(List<? extends Number> list) {
    for (Object e : list) {
        System.out.println(e);
    }
}

μ œλ„€λ¦­ μ™€μΌλ“œ μΉ΄λ“œ 문법은 μžλ°”μ˜ μ œλ„€λ¦­μ—μ„œ κ°€μž₯ λ‚œμ΄λ„κ°€ 높은 뢀뢄이닀. μ–Έμ œ <? extends μƒμœ„νƒ€μž…> λ₯Ό μ¨μ•Όλ˜κ³  μ–Έμ œ <? super ν•˜μœ„νƒ€μž…> μ¨μ•Όν•˜λŠ”μ§€λŠ” ν˜„μ—… κ°œλ°œμžλ„ λ•Œλ•Œλ‘œ μ–΄λ €μ›Œ ν•˜λŠ” 뢀뢄이닀. λ”°λΌμ„œ λ³„λ„μ˜ μ•„λž˜ ν¬μŠ€νŒ…μ„ 톡해 μ œλ„€λ¦­ μ™€μΌλ“œμΉ΄λ“œ μ‚¬μš©λ²•μ„ μ™„λ²½νžˆ 이해해보도둝 ν•˜μž.

 

[JAVA] β˜• μ œλ„€λ¦­ - 곡변성 & μ™€μΌλ“œμΉ΄λ“œ μ™„λ²½ μ΄ν•΄ν•˜κΈ°

μžλ°”μ˜ 곡변성 / λ°˜κ³΅λ³€μ„± μ œλ„€λ¦­μ˜ μ™€μΌλ“œμΉ΄λ“œλ₯Ό 배우기 μ•žμ„œ μ„ μˆ˜ μ§€μ‹μœΌλ‘œ μ•Œκ³  λ„˜μ–΄κ°€μ•Όν•  κ°œλ…μ΄ μžˆλ‹€. 쑰금 λ‚œμ΄λ„ μžˆλŠ” ν”„λ‘œκ·Έλž˜λ° 뢀뢄을 ν•™μŠ΅ ν•˜λ‹€λ³΄λ©΄ ν•œλ²ˆμ―€μ€ λ“€μ–΄λ³Όμˆ˜ μžˆλŠ” 곡변

inpa.tistory.com


μ œλ„€λ¦­ νƒ€μž… μ†Œκ±°

μ œλ„€λ¦­μ€ νƒ€μž… μ•ˆμ •μ„±μ„ μœ„ν•΄ JDK 1.5λΆ€ν„° λ„μž…λœ λ¬Έλ²•μœΌλ‘œ 이전 μžλ°”μ—μ„œλŠ” μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„° 없이 μžλ°” μ–Έμ–΄λ₯Ό μ½”λ”©ν•΄μ™”λ‹€. κ·Έλž˜μ„œ μ΄μ „μ˜ μžλ°” λ²„μ „μ˜ μ½”λ“œμ™€ ν˜Έν™˜μ„±μ„ μœ„ν•΄ μ œλ„€λ¦­ μ½”λ“œλŠ” 컴파일되면 μ œλ„€λ¦­ νƒ€μž…μ€ μ‚¬λΌμ§€κ²Œ λœλ‹€. 즉, 클래슀 파일(.class)μ—λŠ” μ œλ„€λ¦­ νƒ€μž…μ— λŒ€ν•œ μ •λ³΄λŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 것이닀.

μ–΄μ°Œλ³΄λ©΄ μ œλ„€λ¦­μ€ μ‹€μ œ λ°”μ΄νŠΈ μ½”λ“œμ—λŠ” μ—†λŠ” 반μͺ½μ§œλ¦¬ μ–Έμ–΄ 문법이라고 ν• μˆ˜ μžˆλ‹€. κ·Έλž˜μ„œ μ œλ„€λ¦­μ„ κ°œλ°œμžκ°€ 잘λͺ»λœ λ°©ν–₯으둜 섀계λ₯Ό ν•˜λ©΄ 잠재적인 νž™ μ˜€μ—Ό(heap pollution) λ¬Έμ œμ— λΉ μ§€κ²Œ 될 수 μžˆλ‹€. λ”°λΌμ„œ μš°λ¦¬κ°€ λ°”μ΄νŠΈ μ½”λ“œλ₯Ό 보고 μ½”λ”©ν•  것은 μ•„λ‹ˆμ§€λ§Œ, μ˜¬λ°”λ₯΄κ²Œ μ œλ„€λ¦­μ„ μ„€κ³„ν•˜κΈ° μœ„ν•΄μ„  μ œλ„€λ¦­μ˜ 컴파일 과정을 ν•œλ²ˆ μ―€ μ•Œμ•„λ‘˜ ν•„μš”μ„±μ΄ μžˆλ‹€.

 

[JAVA] β˜• μ œλ„€λ¦­ νƒ€μž… μ†Œκ±° 컴파일 κ³Όμ • μ•Œμ•„λ³΄κΈ°

μ œλ„€λ¦­ νƒ€μž… μ†Œκ±° (Erasure) μ œλ„€λ¦­μ€ νƒ€μž… μ•ˆμ •μ„±μ„ 보μž₯ν•˜λ©°, μ‹€ν–‰μ‹œκ°„μ— μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ ν•˜κΈ°μœ„ν•΄ JDK 1.5λΆ€ν„° λ„μž…λœ λ¬Έλ²•μœΌλ‘œ, 이전 μžλ°”μ—μ„œλŠ” μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„° 없이 μžλ°”λ₯Ό

inpa.tistory.com


# 참고 자료

https://www.youtube.com/watch?v=Vv0PGUxOzq0

https://www.youtube.com/watch?v=w5AKXDBW1gQ