본문 바로가기

Java

자바 - 제네릭

목차

  1. 제네릭이란?
  2. 제네릭 클래스
  3. 제네릭 메서드

1. 제네릭이란?

다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시 타입 체크를 해주는 기능

객체의 타입을 컴파일시 체크하기 때문에 객체 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.

 

제네릭의 특징

타입 안정성  

타입체크/형변환 생략으로 코드 간결성

 


 

2. 제네릭 클래스

2.1 제네릭 제한 사항

 - 타입 변수는 인스턴스 변수로 간주, static 멤버가 될 수 없음 

class Box<T> {
    static T item; //에러
    static int compare(T t1, T t2) { //에러
        
    }

 

왜냐하면 제네릭은 인스턴스 별로 다르게 동작하려고 만든 기능이기 때문이다.

 

- 배열 생성 X, 선언만 가능

- 타입 변수는 상속 관계에 있더라도 에러

Box<Fruit> appleBox = new Box<Apple>(); // 에러 (apple의 Fruit의 자손)

 

2.2 제한된 제네릭 클래스

제네릭은 클래스, 메소드의 타입을 제한한다. 하지만 들어갈 수 있는 타입을 제한하진 못한다. 이를 보완하기 위해 상속을 사용한다.

 

제네릭은 클래스, 메소드의 타입을 제한한다. 

FruitBox<Apple> appleBox = new FruitBox<>(); // only Apple
FruitBox<Orang> orangeBox = new FruitBox<>(); // only Orange

 

그러나 들어갈 수 있는 타입을 제한하진 못한다.

FruitBox<NoteBook> appleBox = new FruitBox<>(); // NoteBook 은 넣기 싫은데... 제한하질 못함

 

그래서 상속을 쓴다.

class FruitBox<T extends Fruit> 

 

2.3 와일드 카드, ?

- 생성과 선언에서 타입 변수가 다르다면(상송 관계더라도) 오류

- 타입 변수는 컴파일 단계에서 사라진다. 그래서 오버로딩 되지 않음 

 

그런데 제네릭 클래스를 매개변수로 받는 메서드를 사용하고 싶다. 그래서 고안된 것이 와일드 카드

 

class Juicer {
    static Juice makeJuice(FruitBox<Fruit> box) { //Fruit 은 타입 변수지만 이미 결정됐기 때문에
        String tmp = "";			//static과 함께 사용 가능
        for (Fruit fruit : box.getFruits()) {
            tmp += fruit + " ";
        }
        return new Juice(tmp);
    }

 

하지만 문제는 static 메서드이다. 누구를 넣든 동일하게 동작해야 되기 때문에 자손을 넣을 수 없다. 

(static 메서드가 아니더라도 타입 변수의 특성상 오류 발생한다.)

FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();

System.out.println(juicer.makeJuice(fruitBox)); // OK
System.out.println(juicer.makeJuice(appleBox)); //에러

 

해결책으로 오버로딩. 하지만 제네릭 타입이 다른 것만으로는 오버로딩이 성립하지 않는다. 

제네릭 타입은 컴파일러가 컴파일할 때만 사용하고 제거해버린다.

그래서 두 메서드는 오버로딩이 아니라 메서드 중복 정의

 

그래서 고안된 것이 와일드 카드(?)

 

static Juice makeJuice(FruitBox<? extends Fruit> box) {
    String tmp = "";
    for (Fruit fruit : box.getFruits()) {
        tmp += fruit + " ";
    }
    return new Juice(tmp);
}

Fruit을 상속하는 모든 것을 받을 수 있다는 뜻

 


3. 제네릭 메서드

메서드 선언부에 제네릭 타입이 선언된 메서드를 제네릭 메서드라 한다.

 

제네릭 타입 선언 위치 - 반환 타입 바로 앞 

static <T> void sort(List<T> list, Comparator<? super T> c)

 

 

 

제네릭 메서드 해석

제네릭 메서드를 실제로 만들어 쓰는 것 보단 자바 API를 쓸 때, 제네릭 메서드를 잘 알고 있으면 도움이 될 것 같음

 

public static <T extentds Comparable<? super T>> void sort(List<T> list)

sort 매서드 매개변수 List 는 Comparable 인터페이스를 구현한 것이어야 한다. 그리고 T의 부모는 모두 사용 가능하다.

 

 

 

 

 

 

'Java' 카테고리의 다른 글

Java - 애너테이션  (0) 2023.03.21
자바 - 람다식  (0) 2022.11.26
애노테이션이란?  (0) 2022.07.17
기본형과 참조형 그리고 래퍼클래스  (0) 2022.07.17
this는 왜 사용할까?  (0) 2022.07.15