λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

빈 ꡬ멍 μ±„μš°κΈ°

[Java] μ œλ„€λ¦­

좜처

ChatGPT


μ œλ„€λ¦­μ˜ 쑴재 이유

1. νƒ€μž… μ•ˆμ „μ„± κ°•ν™”

μ œλ„€λ¦­μ„ μ‚¬μš©ν•˜λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ 컴파일 μ‹œμ μ— 잘λͺ»λœ νƒ€μž… μ‚¬μš©μ„ κ²€μΆœν•  수 μžˆλ‹€. 이λ₯Ό 톡해 λŸ°νƒ€μž… μ˜ˆμ™Έλ₯Ό 주리고, νƒ€μž… λ³€ν™˜(casting)에 κ΄€ν•œ 였λ₯˜λ₯Ό λ°©μ§€ν•œλ‹€.

2. μ½”λ“œ μž¬μ‚¬μš©μ„±

λ™μΌν•œ μ½”λ“œκ°€ λ‹€μ–‘ν•œ 데이터 νƒ€μž…κ³Ό ν•¨κ»˜ μ‚¬μš©λ  수 μžˆμ–΄, μ€‘λ³΅λœ μ½”λ“œλ₯Ό 쀄이고 μœ μ§€λ³΄μˆ˜μ„±μ„ 높인닀.

3. 가독성 ν–₯상

μ œλ„€λ¦­μ„ μ‚¬μš©ν•˜λ©΄ λͺ…ν™•ν•œ νƒ€μž… 정보λ₯Ό μž¬κ³΅ν•΄ μ½”λ“œμ˜ 가독성을 높일 수 μžˆλ‹€.

 

μ œλ„€λ¦­ μž₯점

1. 컴파일 μ‹œμ μ˜ νƒ€μž… 체크

μ œλ„€λ¦­μ„ μ‚¬μš©ν•˜λ©΄ 컴파일 μ‹œμ μ—μ„œ νƒ€μž…μ„ μ²΄ν¬ν•˜λ©°, λŸ°νƒ€μž„μ— λ°œμƒν•  수 μžˆλŠ” ClassCastExceptionκ³Ό 같은 μ˜ˆμ™Έλ₯Ό 쀄일 수 μžˆλ‹€.

2. νƒ€μž… λ³€ν™˜μ˜ ν•„μš”μ„± 제거

μ œλ„€λ¦­μ„ μ‚¬μš©ν•˜λ©΄ 객체λ₯Ό μ‚½μž…ν•˜κ±°λ‚˜ μΆ”μΆœν•  λ•Œ νƒ€μž… λ³€ν™˜μ„ μˆ˜λ™μœΌλ‘œ ν•  ν•„μš”κ°€ μ—†μ–΄ μ½”λ“œκ°€ 간결해지고, νƒ€μž… λ³€ν™˜μ—μ„œ λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό 방지할 수 μžˆλ‹€.

3. μ½”λ“œ μž¬μ‚¬μš©μ„±

μ œλ„€λ¦­ 클래슀λ₯Ό λ§Œλ“€λ©΄ λ‹€μ–‘ν•œ νƒ€μž…μ— λŒ€ν•΄ μž¬μ‚¬μš©ν•  수 μžˆμ–΄, μ€‘λ³΅λœ μ½”λ“œλ₯Ό 쀄일 수 μžˆλ‹€.

 

μ œλ„€λ¦­ 단점

1. νƒ€μž… μ†Œκ±° Types Erasure

Java μ œλ„€λ¦­μ€ λŸ°νƒ€μž„μ— νƒ€μž… 정보가 μ†Œκ±°λ˜λ―€λ‘œ, λŸ°νƒ€μž„μ—λŠ” μ œλ„€λ¦­ νƒ€μž… 정보λ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€. 이둜 인해 νŠΉμ • μƒν™©μ—μ„œ μ˜λ„ν•˜μ§€ μ•Šμ€ κ²°κ³Όλ₯Ό μ΄ˆλž˜ν•  수 μžˆλ‹€.

2. κΈ°λ³Έ 데이터 νƒ€μž… μ‚¬μš© μ œν•œ

μ œλ„€λ¦­μ€ int, char λ“± κΈ°λ³Έ 데이터 νƒ€μž…(primitive type)을 직접 μ‚¬μš©ν•  수 μ—†λ‹€. λŒ€μ‹  Integer, Character와 같은 래퍼 클래슀λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

3. λ³΅μž‘ν•œ μ œλ„€λ¦­ νƒ€μž… μ„ μ–Έ

μ œλ„€λ¦­ νƒ€μž…μ΄ λ³΅μž‘ν•΄μ§€λ©΄ μ½”λ“œμ˜ 가독성이 λ–¨μ–΄μ§ˆ 수 μžˆλ‹€.

 

μ‚¬μš© μ‹œ μ£Όμ˜ν•΄μ•Ό ν•  점

1. μ œλ„€λ¦­ νƒ€μž…μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜λŠ” λŸ°νƒ€μž„μ— μ†Œκ±°λœλ‹€. λ”°λΌμ„œ λŸ°νƒ€μž„μ— νƒ€μž… 정보에 μ ‘κ·Όν•˜λ €λŠ” μ‹œλ„λŠ” λ¬΄μ˜λ―Έν•˜λ‹€. 예λ₯Ό λ“€μ–΄, μ œλ„€λ¦­ λ°°μ—΄ 생성은 ν˜€μš©λ˜μ§€ μ•ŠλŠ”λ‹€.('new T[]'와 같은 ν˜•νƒœ)

2. κΈ°λ³Έ 데이터 νƒ€μž… μ‚¬μš© λΆˆκ°€ : μ œλ„€λ¦­μ—μ„œλŠ” κΈ°λ³Έ 데이터 νƒ€μž…(예 : int, char)을 μ‚¬μš©ν•  수 μ—†λ‹€. λŒ€μ‹  Integer, Character와 같은 레퍼 클래슀λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

3. μ œλ„€λ¦­ νƒ€μž… μΊμŠ€νŒ… 주의 : μ œλ„€λ¦­ νƒ€μž…μ˜ 객체λ₯Ό raw type으둜 μΊμŠ€νŒ…ν•  λ•ŒλŠ” κ²½κ³ κ°€ λ°œμƒν•  수 있으며, μ΄λŠ” λŸ°νƒ€μž„ μ˜ˆμ™Έλ₯Ό μœ λ°œν•  수 μžˆλ‹€.

 

예제 μ½”λ“œ

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

// μ œλ„€λ¦­ 클래슀λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.
class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

public class GenericExample {
    public static void main(String[] args) {
        // Integer νƒ€μž…μœΌλ‘œ μ œλ„€λ¦­ 클래슀 μ‚¬μš©
        Box<Integer> integerBox = new Box<>();
        integerBox.setContent(123);
        Integer intValue = integerBox.getContent();
        System.out.println("Integer value: " + intValue);

        // String νƒ€μž…μœΌλ‘œ μ œλ„€λ¦­ 클래슀 μ‚¬μš©
        Box<String> stringBox = new Box<>();
        stringBox.setContent("Hello Generics");
        String strValue = stringBox.getContent();
        System.out.println("String value: " + strValue);

        // μ œλ„€λ¦­ 리슀트λ₯Ό μ‚¬μš©ν•˜λŠ” 예제
        List<String> stringList = new ArrayList<>();
        stringList.add("Apple");
        stringList.add("Banana");

        for (String fruit : stringList) {
            System.out.println(fruit);
        }

        // μ œλ„€λ¦­ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 예제
        System.out.println("Max of 3, 7, 5 is: " + getMax(3, 7, 5));
    }

    // μ œλ„€λ¦­ λ©”μ„œλ“œ μ •μ˜
    public static <T extends Comparable<T>> T getMax(T x, T y, T z) {
        T max = x;
        if (y.compareTo(max) > 0) {
            max = y;
        }
        if (z.compareTo(max) > 0) {
            max = z;
        }
        return max;
    }
}

 

  • Box 클래슀: Box<T>λŠ” μ œλ„€λ¦­ 클래슀둜, ν•˜λ‚˜μ˜ νƒ€μž… λ§€κ°œλ³€μˆ˜ Tλ₯Ό μ‚¬μš©ν•œλ‹€. 이 ν΄λž˜μŠ€λŠ” νƒ€μž…μ— μ•ˆμ „ν•œ λ°©μ‹μœΌλ‘œ 객체λ₯Ό μ €μž₯ν•˜κ³  λ°˜ν™˜ν•  수 μžˆλ‹€.
  • μ œλ„€λ¦­ 리슀트: List<String>은 μ œλ„€λ¦­ νƒ€μž…μ˜ λ¦¬μŠ€νŠΈλ‹€. 이 λ¦¬μŠ€νŠΈλŠ” String νƒ€μž…λ§Œμ„ μ €μž₯ν•  수 있으며, νƒ€μž… μ•ˆμ •μ„±μ„ μ œκ³΅ν•œλ‹€.
  • μ œλ„€λ¦­ λ©”μ„œλ“œ: getMax λ©”μ„œλ“œλŠ” μ œλ„€λ¦­ λ©”μ„œλ“œλ‘œ, <T extends Comparable<T>> νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 비ꡐ κ°€λŠ₯ν•œ νƒ€μž…λ§Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ μ œν•œν•œλ‹€. μ΄λŠ” T νƒ€μž…μ˜ μ„Έ 개의 인자λ₯Ό λ°›μ•„ κ°€μž₯ 큰 값을 λ°˜ν™˜ν•œλ‹€.

 

μ œλ„€λ¦­ νƒ€μž…μ˜ 경계 Generic Type Bounds

1. κΈ°λ³Έ κ°œλ…

μ œλ„ˆλ¦­ νƒ€μž… κ²½κ³„λŠ” μ œλ„€λ¦­ ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λŒ€ νƒ€μž… νŒŒλΌλ―Έν„°μ— ν—ˆμš©ν•  수 μžˆλŠ” μƒμœ„ ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ§€μ •ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€. 즉, μ œλ„€λ¦­ νƒ€μž…μ˜ νŒŒλΌλ―Έν„°κ°€ νŠΉμ • νƒ€μž…μ΄κ±°λ‚˜ νŠΉμ • νƒ€μž…μ˜ μ„œλΈŒνƒ€μž…μ΄μ–΄μ•Ό ν•œλ‹€λŠ” μ œν•œμ„ μ„€μ •ν•˜λŠ” 것이닀.

 

μ œλ„€λ¦­ νƒ€μž…μ˜ κ²½κ³„λŠ” 크게 두 κ°€μ§€λ‘œ λ‚˜λˆŒ 수 μžˆλ‹€.

  • μƒν•œ 경계  Upper Bound : νƒ€μž… νŒŒλΌλ―Έν„°κ°€ νŠΉμ • νƒ€μž…μ˜ ν•˜μœ„ 클래슀(μ„œλΈŒν΄λž˜μŠ€)μ—¬μ•Ό 함을 μ •μ˜ν•œλ‹€.
  • ν•˜ν•œ 경계 Lower Bounde : νƒ€μž… νŒŒλΌλ―Έν„°κ°€ νŠΉμ • νƒ€μž…μ˜ μƒμœ„ 클래슀(슈퍼클래슀)μ—¬μ•Ό 함을 μ •μ˜ν•œλ‹€.

1. μƒν•œ 경계 Upper Bound

μƒν•œ κ²½κ³„λŠ” μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ νŠΉμ • ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†λ°›κ±°λ‚˜, κ·Έ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” νƒ€μž…μ΄μ–΄μ•Ό ν•˜λ‹€λŠ” μ œν•œμ„ μ˜λ―Έν•œλ‹€.

  • 문법 : <T extends μƒμœ„νƒ€μž…>

예제

'<T extends Number>'λŠ” μ œλ„€λ¦­ νƒ€μž… Tκ°€ Number ν΄λž˜μŠ€μ΄κ±°λ‚˜ Number의 ν•˜μœ„ 클래슀(Integer, Doubel, Float λ“±)μ—¬μ•Ό ν•œλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

public class Box<T extends Number> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public double square() {
        return value.doubleValue() * value.doubleValue();
    }
}

 

μœ„ μ½”λ“œμ—μ„œ Box ν΄λž˜μŠ€λŠ” Number νƒ€μž…μ˜ μƒμœ„ 클래슀(λ˜λŠ” μΈν„°νŽ˜μ΄μŠ€)λ₯Ό 가진 νƒ€μž…λ§Œμ„ ν—ˆμš©ν•œλ‹€. Number 클래슀의 ν•˜μœ„ νƒ€μž…μΈ Integer, Double 등을 μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, String λ“± λ‹€λ₯Έ νƒ€μž…μ€ μ‚¬μš©ν•  수 μ—†λ‹€.

 

2. ν•˜ν•œ 경계 Lower Bound

ν•˜ν•œ κ²½κ³„λŠ” μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ νŠΉμ • 클래슀의 μƒμœ„ ν΄λž˜μŠ€μ—¬μ•Ό ν•œλ‹€λŠ” μ œν•œμ„ μ˜λ―Έν•œλ‹€. ν•˜ν•œ κ²½κ³„λŠ” 주둜 μ™€μΌλ“œμΉ΄λ“œ(? super Type)와 ν•¨κ»˜ μ‚¬μš©λœλ‹€.

  • 문법 : <T super ν•˜μœ„ νƒ€μž…> (일반적인 μ œλ„€λ¦­ μ„ μ–Έμ—μ„œλŠ” 직접 μ‚¬μš©ν•˜μ§€ μ•Šκ³ , λ©”μ†Œλ“œ λ§€κ°œλ³€μˆ˜μ—μ„œ μ™€μΌλ“œμΉ΄λ“œ ν˜•νƒœλ‘œ μ‚¬μš©)

예제

'<? super ν•˜μœ„ νƒ€μž…>'λŠ” μ œλ„€λ¦­ νƒ€μž… νŒŒλΌλ―Έν„°κ°€ Integer ν΄λž˜μŠ€μ΄κ±°λ‚˜ Integer의 μƒμœ„ ν΄λž˜μŠ€μ—¬μ•Ό ν•œλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

public static void addIntegers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

 

μœ„ μ½”λ“œμ—μ„œ List<? super Integer>λŠ” Integer νƒ€μž… λ˜λŠ” κ·Έ μƒμœ„ νƒ€μž…μ„ μš”μ†Œλ‘œ κ°€μ§ˆ 수 μžˆλŠ” 리슀트λ₯Ό μ˜λ―Έν•œλ‹€. μ΄λŠ” λ¦¬μŠ€νŠΈμ— μ•ˆμ „ν•˜κ²Œ Integer λ˜λŠ” κ·Έ ν•˜μœ„ νƒ€μž…μ˜ 객체λ₯Ό μΆ”κ°€ν•  수 μžˆλ„λ‘ ν•œλ‹€.

 

2. μ œλ„€λ¦­ νƒ€μž… 경계가 μ‘΄μž¬ν•˜λŠ” 이유

1. νƒ€μž… μ•ˆμ „μ„± 보μž₯

νƒ€μž… κ²½κ³„λŠ” μ»΄νŒŒμΌλŸ¬κ°€ μ œλ„€λ¦­ νƒ€μž…μ΄ ν—ˆμš©ν•  수 μžˆλŠ” νƒ€μž…μ„ μ œν•œν•˜μ—¬ νƒ€μž… μ•ˆμ „μ„±μ„ 보μž₯ν•  수 μžˆλ„λ‘ ν•œλ‹€. 예λ₯Ό λ“€μ–΄, μƒν•œ 경계λ₯Ό μ‚¬μš©ν•˜λ©΄ 잘λͺ»λœ νƒ€μž…μ΄ μ‚¬μš©λ˜λŠ” 것을 λ°©μ§€ν•˜κ³ , ν•˜ν•œ 경계λ₯Ό ν•˜μš©ν•˜λ©΄ νƒ€μž… μ•ˆμ „μ„±μ„ μœ μ§€ν•˜λ©΄μ„œ νŠΉμ • νƒ€μž…μ˜ μΈμŠ€ν„΄λ§Œμ„ μΆ”κ°€ν•  수 μžˆλ‹€.

 

μ˜ˆμ‹œ

λ§Œμ•½ μ œλ„€λ¦­ νƒ€μž…μ— 경계λ₯Ό μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄, 잘λͺ»λœ νƒ€μž…μ΄ μ‚¬μš©λ˜μ–΄ λŸ°νƒ€μž„μ— ClassCastException이 λ°œμƒν•  수 μžˆλ‹€. 경계λ₯Ό μ§€μ •ν•˜λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ 이 같은 였λ₯˜λ₯Ό 미리 방지할 수 μžˆλ‹€.

public <T extends Number> void process(T value) {
    double result = value.doubleValue() * 2;  // Number의 λ©”μ†Œλ“œ μ‚¬μš© κ°€λŠ₯
    System.out.println(result);
}

 

μœ„ μ˜ˆμ œμ—μ„œ T νƒ€μž… νŒŒλΌλ―Έν„°λŠ” Number의 ν•˜μœ„ νƒ€μž…μ΄λ―€λ‘œ, Number ν΄λž˜μŠ€μ— μ •μ˜λœ doubleValue() λ©”μ†Œλ“œλ₯Ό μ•ˆμ „ν•˜κ²Œ ν˜ΈμΆœν•  수 μžˆλ‹€.

2. μ œλ„€λ¦­ λ©”μ†Œλ“œμ˜ μœ μ—°μ„± 증가

μ œλ„€λ¦­ νƒ€μž…μ— μƒν•œμ΄λ‚˜ ν•˜ν•œ 경계λ₯Ό μ§€μ •ν•˜λ©΄, μ œλ„€λ¦­ λ©”μ†Œλ“œμ˜ μ‚¬μš© λ²”μœ„μ™€ μœ μ—°μ„±μ„ 크게 ν–₯μƒμ‹œν‚¬ 수 μžˆλ‹€. 경계가 μ—†λŠ” κ²½μš°λ³΄λ‹€ 더 λ§Žμ€ νƒ€μž…μ„ μ•ˆμ „ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλ‹€.

 

μ˜ˆμ‹œ

μƒν•œ 경계λ₯Ό μ‚¬μš©ν•˜μ—¬ μ œλ„€λ¦­ λ©”μ†Œλ“œλ₯Ό μ„€κ³„ν•˜λ©΄, κ·Έ λ©”μ†Œλ“œλŠ” 더 λ§Žμ€ νƒ€μž…μ„ 받아듀일 수 있으며, λ©”μ†Œλ“œ λ‚΄λΆ€μ—μ„œ νŠΉμ • νƒ€μž…μ— 쒅속적인 κΈ°λŠ₯을 μ•ˆμ „ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€.

public static <T extends Comparable<T>> T findMax(T a, T b) {
    return (a.compareTo(b) > 0) ? a : b;
}

 

μœ„ μ˜ˆμ œμ—μ„œ findMax λ©”μ†Œλ“œλŠ” Comparable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” λͺ¨λ“  νƒ€μž…μ— λŒ€ν•΄ μ‚¬μš©ν•  수 μžˆλ‹€. νƒ€μž… νŒŒλΌλ―Έν„° T에 μƒν•œ 경계λ₯Ό μ„€μ •ν•¨μœΌλ‘œμ¨, λ©”μ†Œλ“œ λ‚΄λΆ€μ—μ„œ compareTo λ©”μ†Œλ“œλ₯Ό μ•ˆμ „ν•˜κ²Œ ν˜ΈμΆœν•  수 있게 λœλ‹€.

3. μ½”λ“œ μž¬μ‚¬μš©μ„±κ³Ό μœ μ§€λ³΄μˆ˜μ„± ν–₯상

μ œλ„€λ¦­ νƒ€μž… 경계λ₯Ό μ‚¬μš©ν•˜λ©΄, μ½”λ“œ μž¬μ‚¬μš©μ„±μ„ 높일 수 있으며, μœ μ§€λ³΄μˆ˜μ„±μ„ ν–₯μƒμ‹œν‚¬ 수 μžˆλ‹€. μ œλ„€λ¦­ ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œκ°€ νŠΉμ • νƒ€μž…μ— 쒅속적이지 μ•ŠκΈ° λ•Œλ¬Έμ—, λ‹€μ–‘ν•œ νƒ€μž…μ„ μ§€μ›ν•˜λŠ” 더 일반적인 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

 

μ˜ˆμ‹œ

μ—¬λŸ¬ 데이터 νƒ€μž…μ— λŒ€ν•΄ λ™μΌν•œ λ‘œμ§μ„ μ μš©ν•΄μ•Ό ν•˜λŠ” 경우, μ œλ„€λ¦­ νƒ€μž… 경계λ₯Ό μ‚¬μš©ν•˜μ—¬ 쀑볡 μ½”λ“œλ₯Ό 쀄이고, μž¬μ‚¬μš© κ°€λŠ₯ν•œ λ©”μ†Œλ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

public static <T extends Number> double sum(List<T> list) {
    double sum = 0.0;
    for (T number : list) {
        sum += number.doubleValue();
    }
    return sum;
}

 

μœ„ μ˜ˆμ œμ—μ„œ sum λ©”μ†Œλ“œλŠ” Number의 ν•˜μœ„ 클래슀(Integer, Double, Float, λ“±)둜 κ΅¬μ„±λœ λ¦¬μŠ€νŠΈμ— λŒ€ν•΄ μ‚¬μš©ν•  수 있으며, λ‹€μ–‘ν•œ νƒ€μž…μ˜ λ¦¬μŠ€νŠΈμ— λŒ€ν•΄ λ™μΌν•œ ν•©μ‚° λ‘œμ§μ„ μž¬μ‚¬μš©ν•  수 μžˆλ‹€.

4. νƒ€μž… μ•ˆμ „μ„±μ„ μœ μ§€ν•˜λ©° λ³€μ„±(Variance) 처리 κ°€λŠ₯

μ œλ„€λ¦­ νƒ€μž…μ˜ κ²½κ³„λŠ” 변성을 μ§€μ›ν•˜λŠ” 데에도 μ€‘μš”ν•œ 역할을 ν•œλ‹€. μƒν•œ 경계와 ν•˜ν•œ 경계λ₯Ό μ΄μš©ν•˜μ—¬ 곡변성(Covariance)와 λ°˜κ³΅λ³€μ„±(Contravariance)λ₯Ό μ²˜λ¦¬ν•  수 μžˆλ‹€.

 

  • μƒν•œ 경계(? extends T): 곡변성 처리λ₯Ό μœ„ν•΄ μ‚¬μš©λœλ‹€. 예λ₯Ό λ“€μ–΄, λ©”μ†Œλ“œ λ§€κ°œλ³€μˆ˜μ—μ„œ μ œλ„€λ¦­ νƒ€μž…μ˜ μƒμœ„ 경계λ₯Ό μ •μ˜ν•˜μ—¬, ν•΄λ‹Ή νƒ€μž…μ˜ ν•˜μœ„ νƒ€μž… 객체듀을 μ•ˆμ „ν•˜κ²Œ λ‹€λ£° 수 μžˆλ‹€.
  • ν•˜ν•œ 경계(? super T): λ°˜κ³΅λ³€μ„± 처리λ₯Ό μœ„ν•΄ μ‚¬μš©λœλ‹€. λ©”μ†Œλ“œ λ§€κ°œλ³€μˆ˜μ—μ„œ μ œλ„€λ¦­ νƒ€μž…μ˜ ν•˜μœ„ 경계λ₯Ό μ •μ˜ν•˜μ—¬, ν•΄λ‹Ή νƒ€μž…μ˜ μƒμœ„ νƒ€μž… 객체듀을 μ•ˆμ „ν•˜κ²Œ λ‹€λ£° 수 μžˆλ‹€.