infinity : 무한한 성장가능성

자바 제네릭 완전정복 (2) 본문

Develop/💜Java

자바 제네릭 완전정복 (2)

인피니 2024. 2. 18. 16:19

저번 편에 이은 자바 제네릭 완전정복 뽀개기 두 번째 글입니다..!

제네릭 메서드와 와일드카드의 개념을 학습하기 전 제네릭 클래스의 타입 인자를 제한하는 법부터 정리해 보겠습니다.

제네릭 클래스의 타입 인자 제한하기


public class Box <T extends Number>{

}

 

위처럼 extends 키워드를 사용해  T extends Number이라는 Box 클래스를 정의할 경우 타입 인자로 Number or Number을 상속하는 클래스만 올 수 있게 됩니다. 

타입인자를 제한하는데 올 수 있는 것으로는 클래스, 인터페이스가 있습니다. 

 

 

제네릭 메서드


선언부에 제네릭으로 리턴 타입, 파라미터의 타입이 정해지는 메서드이다.

제네릭에 대한 예를 보면서 제네릭 메서드에 대해 이해해 보자.

먼저 제네릭을 static 필드변수에 사용한다면? 

public class Box <T>{
    public static T food;
}

위처럼 사용할 경우 컴파일러에서 에러를 알려준다.

위와 같은 에러가 뜨는 이유는 static 은 클래스가 생성되기 전에 메모리에 올라가는데 food의 타입인 T 가 결정되지 않았기 때문에 사용불가능하다.

public class Box <T>{
    private static T food;

    public static T getFood() {
        return food;
    }
}

-> 제네릭을 사용한 static 메서드 또한 컴파일러에서 위와 동일한 에러를 보여준다.

-> static 메서드 또한 클래스가 인스턴스화되기 전에 메모리에 올라가는데 타입이 정해히지 않았기 때문에 사용불가능하다.

하지만 제네릭 메서드는 static 이 가능하다.

 

public class Box <T>{

    public static <T> T getBoxContends(T t) {
        return t;
    }
}

-> static 그리고 반환형을 알려주는 T 사이의 <T>는 T 가 타입 매개 변수임을 알려주는 변수이다. 

 

public class Main{

    public static void main(String[] args) {

        Food box1 = Box.<Food>getBoxContends(new Food());
        Food box2 = Box.getBoxContends(new Food());
    }
}

-> 매개변수에 전달되는 T의 타입을 컴파일러가 확인해 T 의 타입을 유추할 수 있다.

 

와일드카드


제네릭 타입을 선언하는 타입 매개변수에 ? 를 사용하는 것이다.

public class Box <T>{
    public static <T> Box<T> getBox1(Box<T> t) {
        return t;
    }

    public static Box<?> getBox2(Box<?> t) {
        return t;
    }
}

위의 getBox1 이랑 getBox2는 동일한 기능을 제공하는 제네릭 메서드이다.

? 를 통해 와일드카드를 통해 제네릭 메서드를 사용할 경우 getBox1의 메서드처럼 T 가 타입매개변수임을 알려주지 않아도 되기 때문에 

간편해서 종종 사용한다. 

 

와일드카드의 상한과 하한의 제한 


상한 제한된 와일드카드

    public static Box<? extends Number> getBox2(Box<? extends Number> t) {
        return t;
    }

위의 제네릭 클래스의 타입 인자 제한하기와 동일하게 extends 키워드를 사용해 와일드카드의 타입을 제한한다. 

-> Number 또는 Number를 상속하는 하위클래스 (자식클래스)만 올 수 있다.

 

하한 제한된 와일드카드

    public static Box<? super Long> getBox2(Box<? super Long> t) {
        return t;
    }

->  Long 타입으로 하한 제한했을 경우 Long 또는 Long 이 상속하는 클래스여야 한다.

-> 즉 Long의 상위 부모클래스만 올 수 있다,

-> 최소 Long 은 만족해야 한다.. 느낌으로 이해하면 좋을 것 같다. 

-> 위에서 ? 에 올 수 있는 것은 Long, Number, Object이다. 

 

 

제네릭 코드 분석하기 

  public MyBatisBatchItemWriterBuilder<T> itemToParameterConverter(Converter<T, ?> itemToParameterConverter) {
    this.itemToParameterConverter = itemToParameterConverter;
    return this;
  }

위의 메서드를 분석해 보면 MybatisBatchItemWriterBuilder <T>를 반환하는 메서드이고 매개변수로 Converter<T,?> 가 선언된 메서드이다. 해당 메서드를 사용하기 위해서는 메서드의 인자값으로 Converter<T,?> 타입을 넘겨주면 된다.!

 

항상 제네릭의 공부를 미루고 미뤘었는데 요번에 글을 쓰면서 제네릭에 대해 완전히 정리가 된 거 같다.!

물론 제네릭 관련 모든 개념을 다룬 것은 아니지만 코드에서 주로 보았던 개념들에 대해서는 다룬 거 같아 추후 포스팅에서 다루지 않은 제네릭인데 궁금한 것들이 있으면 추가 시리즈로 포스팅할 예정입니다.!

 

 

참고: https://devlog-wjdrbs96.tistory.com/201

'Develop > 💜Java' 카테고리의 다른 글

MapStruct 에 대해 알아보자  (0) 2025.01.19
ModelMapper 에 대해 알아보자  (0) 2025.01.05
자바 제네릭 완전정복 (1)  (1) 2024.01.21