Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Java Generic μ΄λž€?

Table of contents

  1. Generic의 μž₯점
    1. μž₯점을 μ˜ˆμ‹œλ‘œ μ•Œμ•„λ³΄μž
  2. μ œλ„€λ¦­ μ‚¬μš© μ‹œ 주의점
    1. μ œλ„€λ¦­ ν΄λž˜μŠ€μ™€ μ œλ„€λ¦­ λ©”μ„œλ“œμ˜ νƒ€μž…κΈ°ν˜ΈλŠ” 동일 νƒ€μž…μ΄ μ•„λ‹ˆλ‹€.
    2. μ œλ„€λ¦­ ν΄λž˜μŠ€λŠ” λ‹€ν˜•μ„±μ„ ν—ˆμš©ν•˜μ§€λ§Œ, λͺ…μ‹œν•œ νƒ€μž… κΈ°ν˜ΈλŠ” λ‹€ν˜•μ„±μ΄ ν—ˆμš©λ˜μ§€ μ•ŠλŠ”λ‹€.
  3. μ œλ„€λ¦­ νƒ€μž… μ œν•œκ³Ό μ™€μΌλ“œ μΉ΄λ“œ
    1. μ œλ„€λ¦­ νƒ€μž… μ™€μΌλ“œ μΉ΄λ“œ

μ–΄λ–€ 값이 ν•˜λ‚˜μ˜ μ°Έμ‘° μžλ£Œν˜•μ΄ μ•„λ‹Œ μ—¬λŸ¬ μ°Έμ‘° μžλ£Œν˜•μ„ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν”„λ‘œκ·Έλž˜λ° ν•˜λŠ” 것을 β€˜μ œλ„€λ¦­(Generic) ν”„λ‘œκ·Έλž˜λ°β€™ 이라고 ν•œλ‹€.

μžλ£Œν˜• λ³„λ‘œ λ©”μ„œλ“œλ₯Ό λ§Œλ“€λ©΄ μ½”λ“œμ˜ νš¨μœ¨μ„±μ΄ 떨어지기 λ•Œλ¬Έμ—, μ—¬λŸ¬ μ°Έμ‘° μžλ£Œν˜•μ΄ 쓰일 수 μžˆλŠ” 곳에 νŠΉμ •ν•œ μžλ£Œν˜•μ„ μ§€μ •ν•˜μ§€ μ•Šκ³ ,

ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œ ν›„ μ‚¬μš©ν•˜λŠ” μ‹œμ μ— μ–΄λ–€ μžλ£Œν˜•μ„ μ‚¬μš©ν•  것인지 μ§€μ •ν•˜λŠ” 방식이닀.

Generic의 μž₯점

  • μ œλ„€λ¦­μ€ μ°Έμ‘° μžλ£Œν˜•μ΄ λ³€ν™˜λ  λ•Œ 이에 λŒ€ν•œ 검증을 μ»΄νŒŒμΌλŸ¬κ°€ ν•˜λ―€λ‘œ μ•ˆμ •μ 
  • 클래슀 μ™ΈλΆ€μ—μ„œ νƒ€μž…μ„ 지정해주기 λ•Œλ¬Έμ— λ”°λ‘œ νƒ€μž…μ„ μ²΄ν¬ν•˜κ³  λ³€ν™˜ν•΄μ€„ ν•„μš”κ°€ μ—†λ‹€.
  • λΉ„μŠ·ν•œ κΈ°λŠ₯을 μ§€μ›ν•˜λŠ” 경우 μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ΄ 높아진닀.

μž₯점을 μ˜ˆμ‹œλ‘œ μ•Œμ•„λ³΄μž

public class Test {
    public static void main(String[] args) {
        Sample sample = new Sample();
        int i = sample.get(1);
        String text = sample.get("λ¬Έμžμ—΄");
    }
}

class Sample{
    String get(String input) {
        return input;
    }
    int get(int input) {
        return input;
    }
}

μœ„μ™€ 같이 νŒŒλΌλ―Έν„°λ‘œ Stringκ³Ό int νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό λ°›λŠ” λ©”μ„œλ“œκ°€ μžˆλ‹€κ³  ν• λ•Œ,

μžλ£Œν˜•μ— 맞게 λ©”μ„œλ“œ 2개λ₯Ό μ˜€λ²„λ‘œλ”©ν•΄μ„œ κ΅¬ν˜„ν•΄λ„ λ˜μ§€λ§Œ,


class Sample{
    Object get(Object input) {
        return input;
    }
}

κ°€μž₯ μƒμœ„ 객체인 Objectλ₯Ό μ΄μš©ν•΄μ„œ, μœ„μ™€ 같이 λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•΄λ„ 될 것이닀.

ν•˜μ§€λ§Œ, μœ„ 방식은 단점이 μžˆλŠ”λ° μš°λ¦¬κ°€ μ›ν–ˆλ˜ κΈ°λŠ₯은 String을 μž…λ ₯ν•˜λ©΄ String λ¬Έμžμ—΄μ„ λ°˜ν™˜λ°›μ•˜κ³ , intλ₯Ό μž…λ ₯ν•˜λ©΄ intλ₯Ό λ°˜ν™˜λ°›μ•˜λ‹€.


public class Test {
    public static void main(String[] args) {
        Sample sample = new Sample();
        String text = (String)sample.get("text");
        int i = (int) sample.get(1);
    }
}

λͺ¨λ“  클래슀의 쑰상인 Objectλ₯Ό μž…λ ₯λ°›μ•„ Objectλ₯Ό λ°˜ν™˜ν•˜λ―€λ‘œ λ²”μš©μ„±μ΄ μ’‹λ‹€κ³  ν•  수 μžˆμ§€λ§Œ,

λ‹€μ‹œ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ λ°˜ν™˜λ°›κΈ° μœ„ν•΄μ„œλŠ” Casting μž‘μ—…μ΄ μˆ˜λ°˜λœλ‹€.


public class Test {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("λ¬Έμžμ—΄");
        String str = list.get(0); //πŸ’‘list.get() ν•΄μ„œ λ‚˜μ˜¨ κ°μ²΄λŠ” Objectμ΄λ―€λ‘œ 컴파일 μ—λŸ¬ λ°œμƒ 
    }
}

μš°λ¦¬κ°€ 리슀트 μ»¬λ ‰μ…˜μ„ μ‚¬μš©ν•  λ•Œλ„ μœ„μ™€ 같은 이유둜 μ œλ„€λ¦­ νƒ€μž…μ„ 항상 λͺ…μ‹œν•΄μ£ΌλŠ” μ΄μœ μ΄λ‹€.

πŸ’‘ μœ„ 상황은 List에 νƒ€μž…μ„ λͺ…μ‹œν•΄μ£Όμ§€ μ•Šμ„ 경우 Object둜 보관을 ν•˜κΈ° λ•Œλ¬Έμ—,

λ°˜ν™˜ν•  λ•ŒλŠ” λ‹€μ‹œ String ν˜•λ³€ν™˜μ„ ν•΄μ£Όμ–΄μ•Ό μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

List<String> list = new ArrayList<>(); 둜 listλ₯Ό μƒμ„±ν•˜λ©΄ String νƒ€μž…μ˜ 객체만 μž…λ ₯됨을 보μž₯ν•΄μ£ΌκΈ° λ•Œλ¬Έμ— Casting(ν˜• λ³€ν™˜) 없이 String으둜 λ°˜ν™˜λ°›μ„ 수 있던 것이닀.


🌟 결둠은 이 λͺ¨λ“  단점을 ν•΄κ²°ν•΄μ£ΌλŠ” 방식이 μ œλ„€λ¦­ 방식인 것이닀.

class Sample{
    <T> T get(T input) {
        return input;
    }
}

λ©”μ„œλ“œ μ•žμ— <T>(κΌ­ Tκ°€ μ•„λ‹ˆμ–΄λ„ 됨) 와 같이 <> μ•ˆμ— νƒ€μž… 기호λ₯Ό μ •μ˜ν•΄μ„œ μ œλ„€λ¦­μ΄λΌλŠ” ν‘œμ‹œλ₯Ό ν•΄μ£Όκ³  λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λœλ‹€.

μ΄λŸ°μ‹μœΌλ‘œ μ œλ„€λ¦­ λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•˜λ©΄, TλΌλŠ” νƒ€μž…μ΄ λ“€μ–΄μ™€μ„œ TλΌλŠ” νƒ€μž…μœΌλ‘œ λ°˜ν™˜λ¨μ„ λͺ…μ‹œν•΄μ£Όμ—ˆκΈ° λ•Œλ¬Έμ—,

ν˜•λ³€ν™˜λ„ ν•„μš”μ—†κ³  μ€‘λ³΅λ˜λŠ” λ©”μ„œλ“œλ„ 쀄일 수 μžˆλ‹€.

μ œλ„€λ¦­ λ©”μ„œλ“œλ₯Ό μ˜ˆμ‹œλ‘œ λ“€μ—ˆμ§€λ§Œ, μ œλ„€λ¦­ ν΄λž˜μŠ€λ„ μœ„μ™€ 같은 이유둜 μ‚¬μš©λœλ‹€.


class Sample <T> {
    T value;
    public Sample(T t){
        this.value = t;
    }
	T get(){
        return value;
    }
}

μ œλ„€λ¦­ ν΄λž˜μŠ€λŠ” μœ„μ™€ 같이 클래슀 λ ˆλ²¨μ— <νƒ€μž… 기호>λ₯Ό λͺ…μ‹œν•˜κ³  μ‚¬μš©ν•˜λ©΄ λœλ‹€.


μ œλ„€λ¦­ μ‚¬μš© μ‹œ 주의점

μ œλ„€λ¦­ ν΄λž˜μŠ€μ™€ μ œλ„€λ¦­ λ©”μ„œλ“œμ˜ νƒ€μž…κΈ°ν˜ΈλŠ” 동일 νƒ€μž…μ΄ μ•„λ‹ˆλ‹€.

class Sample <T> {
    T value;
    public Sample(T t){
        this.value = t;
    }
    
    <T> T getInput(T input) {
        return input;
    }
}

μœ„μ™€ 같이 μ œλ„€λ¦­ ν΄λž˜μŠ€μ™€ μ œλ„€λ¦­ λ©”μ„œλ“œκ°€ ν•¨κ»˜ μžˆλŠ” ν΄λž˜μŠ€κ°€ μžˆμ„ λ•Œ,

μ œλ„€λ¦­ λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν•œ T와 ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©ν•œ TλŠ” 동일 νƒ€μž…μ΄ μ•„λ‹ˆλΌλŠ” 것을 μ£Όμ˜ν•΄μ•Όν•œλ‹€.


public class Test {
    public static void main(String[] args) {
        Sample<Integer> sample = new Sample(1);
        System.out.println(sample.getInput("μ•ˆλ…•").getClass());
    }
}

Sample 객체λ₯Ό 생성할 λ•Œ, μ œλ„€λ¦­ νƒ€μž…μ„ Integerλ₯Ό λͺ…μ‹œν–ˆμ§€λ§Œ μœ„ μ½”λ“œλŠ” getInput() νŒŒλΌλ―Έν„°λ‘œ λ¬Έμžμ—΄μ„ 넣어도 정상 λ™μž‘ν•˜κ³ 

getClass()λ₯Ό ν–ˆμ„ λ•Œ, String ν΄λž˜μŠ€κ°€ λ‚˜μ˜€λŠ” 것을 확인할 수 μžˆλ‹€.

즉 독립적인 νƒ€μž…μ΄λΌλŠ” 것을 μ•Œ 수 μžˆλ‹€.


class Sample <T> {
    T value;
    public Sample(T t){
        this.value = t;
    }
    
    T getInput(T input) {
        return input;
    }
}

클래슀 λ ˆλ²¨μ—μ„œ μ‚¬μš©ν•œ νƒ€μž… 기호λ₯Ό λ©”μ„œλ“œλ ˆλ²¨μ—μ„œλ„ μ μš©μ‹œν‚€κ³  μ‹Άλ‹€λ©΄ λ©”μ„œλ“œ μ•žμ— λ³„λ„μ˜ μ œλ„€λ¦­ ν‘œμ‹œλ₯Ό μ œμ™Έν•˜κ³  λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•΄μ•Όν•œλ‹€.


μ œλ„€λ¦­ ν΄λž˜μŠ€λŠ” λ‹€ν˜•μ„±μ„ ν—ˆμš©ν•˜μ§€λ§Œ, λͺ…μ‹œν•œ νƒ€μž… κΈ°ν˜ΈλŠ” λ‹€ν˜•μ„±μ΄ ν—ˆμš©λ˜μ§€ μ•ŠλŠ”λ‹€.

public class Test {
    public static void main(String[] args) {
        Dad<String> dad = new Son<>();
    }
}
class Son <T> extends Dad{
    T value;
}
class Dad<T>{
}

μœ„μ™€ 같이 두 μ œλ„€λ¦­ ν΄λž˜μŠ€κ°€ 상속관계에 μžˆμ„ λ•ŒλŠ”, λ‹€ν˜•μ„±μœΌλ‘œ μ œλ„€λ¦­ 객체λ₯Ό 생성할 수 μžˆμ§€λ§Œ


public class Test {
    public static void main(String[] args) {
        Family<Dad> family = new Family<Son>(); //πŸ’‘ μ—λŸ¬ λ°œμƒ!
    }
}

class Family<T>{
    T value;
}

class Son extends Dad{
}
class Dad{
}

μœ„μ™€ 같이 μ œλ„€λ¦­ νƒ€μž…μ€ λ‹€ν˜•μ„±μ΄ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.

<> μ•ˆμ— λ“€μ–΄κ°€λŠ” μ œλ„€λ¦­ νƒ€μž… κΈ°ν˜ΈλŠ” 무쑰건 λ™μΌν•΄μ•Όν•˜κ³ ,

λ”°λΌμ„œ Sample<Dad> sample = new Sample<>(); 처럼 μƒλž΅μ΄ κ°€λŠ₯ν•˜λ‹€.


μ œλ„€λ¦­ νƒ€μž… μ œν•œκ³Ό μ™€μΌλ“œ μΉ΄λ“œ

public class Test {
    public static void main(String[] args) {
        Family<Dog> family = new Family<>();
    }
}

class Family<T>{
    T value;
}
class Dog{
}
class Son extends Dad{
}
class Dad{
}

μœ„ μƒν™©μ—μ„œ μ œλ„€λ¦­ 클래슀인 Family에 Dog 클래슀둜 λͺ…μ‹œν•˜μ§€ λͺ»ν•˜λ„둝 νŠΉμ • νƒ€μž…μ„ μ œν•œν•˜λŠ” 방법은 extendsλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

<T extends 클래슀> 둜 μ œλ„€λ¦­μ„ λͺ…μ‹œν•˜λ©΄ 클래슀의 μžμ† νƒ€μž…λ§Œ λŒ€μž…λ  수 μžˆλ‹€.


public class Test {
    public static void main(String[] args) {
        Family<Dog> family = new Family<>(); //πŸ’‘ Dog ν΄λž˜μŠ€λŠ” Dadλ₯Ό μƒμ†λ°›λŠ” ν΄λž˜μŠ€κ°€ μ•„λ‹ˆλ‹€.
    }
}

class Family<T extends Dad>{
    T value;
}
class Dog{
}
class Son extends Dad{
}
class Dad{
}

μœ„ μ½”λ“œλŠ” Dad 클래슀λ₯Ό μƒμ†ν•˜λŠ” 클래슀만 μ œν•œμ„ λ‘μ—ˆκΈ° λ•Œλ¬Έμ— Dog 클래슀λ₯Ό λŒ€μž…ν•˜λ €κ³  ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•˜κ²Œ λœλ‹€.

⚠️ λ§Œμ•½ νŠΉμ • μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 객체둜 μ œν•œν•˜κ³  싢은 κ²½μš°μ—λ„ implementsκ°€ μ•„λ‹Œ extendsλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.


μ œλ„€λ¦­ νƒ€μž… μ™€μΌλ“œ μΉ΄λ“œ

public class Test {
    public static void main(String[] args) {
        Ex.getName(new Family<Dad>());
        Ex.getName(new Family<Son>());
    }
}

class Ex{
    static void getName(Family<Dad> family) {
    }
    
    static void getName(Family<Son> family) { //πŸ’‘ 컴파일 μ—λŸ¬ λ°œμƒ
    }
}
class Family<T extends Dad>{
    T value;
}

class Son extends Dad{
}
class Dad{
}

쑰금 μ–΅μ§€μŠ€λŸ¬μšΈ 수 μžˆκ² μ§€λ§Œ, μœ„μ™€ 같은 μ½”λ“œκ°€ μžˆλ‹€κ³  μƒκ°ν•΄λ³΄μž.

Family κ°μ²΄λŠ” Family<Dad> family = new Family<>(); ν˜Ήμ€ Family<Son> family = new Family<>(); 둜 생성될 수 있고


이λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ λ°›μ•„ μ²˜λ¦¬ν•˜λŠ” λ©”μ„œλ“œλ₯Ό λ§Œλ“ λ‹€κ³  생각해보면,

μœ„μ™€ 같이 νƒ€μž… κΈ°ν˜Έμ•ˆμ— μžˆλŠ” κ°μ²΄λŠ” λ‹€ν˜•μ„±μ΄ μ„±λ¦½ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— getName() λ©”μ„œλ“œλ₯Ό 2개 μ •μ˜ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.


ν•˜μ§€λ§Œ, μ»΄νŒŒμΌμ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

μ΄μœ λŠ” μ œλ„€λ¦­ νƒ€μž…μ΄ λ‹€λ₯Έκ²ƒ λ§ŒμœΌλ‘œλŠ” μ˜€λ²„λ‘œλ”©μ΄ μ„±λ¦½ν•˜μ§€ μ•Šμ•„μ„œ, λ©”μ„œλ“œ 쀑볡 μ •μ˜ 문제둜 컴파일 μ—λŸ¬κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

μ΄λŸ΄λ•Œ μ‚¬μš©ν•  수 μžˆλŠ” 것이 ? λ₯Ό μ΄μš©ν•œ μ™€μΌλ“œ μΉ΄λ“œμ΄λ‹€.


public class Test {
    public static void main(String[] args) {
        Ex.getName(new Family<Dad>());
        Ex.getName(new Family<Son>());
    }
}

class Ex{
    static void getName(Family<? extends Dad> family) {
    }
}
class Family<T extends Dad>{
    T value;
}

class Son extends Dad{
}
class Dad{
}

μœ„μ™€ 같이 νŒŒλΌλ―Έν„°μ— <? extends Dad> 둜 λͺ…μ‹œν•΄μ£Όμ—ˆκ³ , μ΄λŠ” Dadλ₯Ό μƒμ†ν•˜λŠ” 클래슀둜 νƒ€μž…μ„ μ§€μ •ν•œ μ œλ„€λ¦­ 클래슀λ₯Ό 받을 수 μžˆμŒμ„ μ˜λ―Έν•œλ‹€.

<? super Dad> 와 같이 super ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ Dad와 Dad클래슀의 쑰상 클래슀둜 μ œν•œν•  수 μžˆλ‹€.


μ°Έκ³ ν•œ κΈ€

  1. μžλ°”μ˜ 정석