제네릭

작성일

제네릭이란?

클래스나 메소드에서 사용할 내부 데이터 타입을 외부에서 지정하는 기법

제네릭 클래스

클래스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스라 한다.

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

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

클래스 옆에 꺽쇠괄호와 타임 매개변수를 적어주면 된다.(여기서 T가 타입 매개변수이다.)

제네릭의 사용이유

1.타입 안정성

클래스

class Apple {}
class Banana {}
class FruitBox {
    private Object fruit;
    public FruitBox (Object fruit) {
        this.fruit = fruit;
    }

    pbulic Object getFruit() {
        return fruit;
    }
}

정상코드

public static void main(String[] args) {
    FruitBox appleBox = new FruitBox(new Apple());
    FruitBox bananaBox = new FruitBox(new Banana());
    Apple apple = (Apple) appleBox.getFruit();
    Banana banana = (Banana) bananaBox.getFruit();
}

에러코드

public static void main(String[] args) {
    FruitBox appleBox = new FruitBox(new Apple());
    FruitBox bananaBox = new FruitBox(new Banana());
    Apple apple = (Apple) appleBox.getFruit();
    Banana banana = (Banana) appleBox.getFruit();
}

실행하기 전엔 모른다.
즉 제네릭을 사용하지 않았을 때엔 appleBox에서 가져온 과일을 바나나에 대입해버렸는지, 아니였는지 모른다.
위를 제네릭 클래스로 작성했을 시,

제네릭클래스

class Apple {}
class Banana {}
class FruitBox<T> {
    private T fruit;
    public FruitBox (T fruit) {
        this.fruit = fruit;
    }

    pbulic T getFruit() {
        return fruit;
    }
}

제네릭을 사용하고 아까와 같은 에러코드

public static void main(String[] args) {
    FruitBox appleBox = new FruitBox(new Apple());
    FruitBox bananaBox = new FruitBox(new Banana());
    Apple apple = (Apple) appleBox.getFruit();
    Banana banana = (Banana) appleBox.getFruit();
}

이런 코드 작성 실수를 하면, 바로 IntelliJ가 인식을 하여서 컴파일 에러를 발생시켜 준다,

2.캐스팅 삭제

비제네릭 클래스

public static void main(Stirng[] aggs) {
    Fruit appleBox = new FruitBox(new Apple());
    Fruit bananaBox = new FruitBox(new Banana());
    Apple apple = (Apple) appleBox.getFruit();
    Banana banana = (Banana) bananaBox.getFruit();

}

제네릭 클래스 public static void main(String[] args) { FruitBox appleBox = new FruitBox<>(new Apple()); FruitBox bananaBox = new FruitBox<>(new Banana()); Apple apple = appleBox.getFruit; Banana banana = bananaBox.getFruit; } 캐스팅이 사라진다. 오브젝트 클래스는 사용하는 타입에 맞게 캐스팅을 해줘야만 하지만, 제네릭은 컴파일 타임에 미리 타입이 지정되므로 형변환을 하지 않아도 된다.

제네릭을 사용하는 이유

  • 컴파일 타임에 자료형의 오류에 대한 검증을 수행하여 런타임에 자료형에 안전한 코드를 실행한다.
  • 반환값에 대한 타입 변환 및 타임 검사에 들어가는 노력을 줄일수 있고, 형변환이 없어지므로 가독성이 좋아진다.

제네릭 메소드의 형태

  • <> 안의 타입으로 매개변수의 데이터 타입을 지정
  • 타입 파라미터의 범위는 메소드 블록 이내로 한정
public <T> void add(T t) {
    // ...
}

제네릭 메소드는 제네릭 클래스가 아니더라도 정의할 수 있다

class Name {
    public <T> void printClassname(T t) {
        System.out.println(t.getClass().getName());
    }
}
public static void main(Stirng[] args) {
    Name name= new Name();
    name.printClassName(1);
    name.printClassName(3.14);
}

실행 결과값

java.lang.Integer
java.lang.Double

타입 매개변수의 제한

상한 경계

T extends Fruit

  • 타입 매개변수의 클래스는 Fruit 클래스이거나 Fruit의 하위 클래스이어야 한다.
class FruitBox<T extends Fruit> {
    private List<Fruit> fruits = new ArrayList<>();

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

하한 경계

T super Fruit

  • 타입 매개변수의 클래스는 Fruit 클래스이거나 Fruit의 상위 클래스이어야 한다.

비경계 와일드카드

  • ?의 형태로 사용, 예를 들어, List<?>
  • 모든 타입이 인자가 될 수 있다.
public static void printList(List<?> list) {
    for (Object elem : list) {
        System.out.println(elem + " ");
    }

    System.out.println();
}
List <String> strings =new ArrayList<>();
printList(strings);

비경계 와일드 카드의 특징

List<?>에서 Get한 원소는 Object 타입이다

1.비경계 와일드카드의 원소는 어떤 타입도 될 수 있다.

  • 어떤 타입이 와도 읽을 수 있도록, 모든 타입의 공통 조상인 Object로 받는다

2.List<?>에는 null만 삽입할 수 있다.

  • 비경계 와일드카드의 원소가 어떤 타입인지 알 수 없다. 그러므로 타입 안정성을 지키기 위해 null만 삽입할 수 있다.

상한 경계 와일드카드

  • ? extends T의 형태로 사용. 예를 들어, List<? extends T>
  • T 혹은 T의 하위 클래스만 인자로 올 수 있다.

상한 경계 와일드카드의 특징

  • 상한 경계 와일드카드의 원소는 T 혹은 T의 하위 클래스이다.
  • 원소들의 최고 공통 조상인 T로 읽으면, 어떤 타입이 오든 T로 읽을 수 있다.
  • List<? extends T>에는 null만 삽입할 수 있다.

하한 경계 와일드카드의 특징

  • ? super T의 형태로 사용. 예를 들어, List<? super T>
  • T 혹은 T의 상위 클래스만 인자로 올 수 있다.
  • T 하한 경계 와일드카드의 원소는 T의 상위클래스 중 어떤 타입도 될 수 있다. 어떤 타입이 와도 읽을 수 있도록,
    T들의 공통 조상인 Object를 받는다.

참고자료

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