elevne's Study Note

Java의정석 공부 - (5: Generics) 본문

Backend/Java

Java의정석 공부 - (5: Generics)

elevne 2023. 2. 2. 18:01

Generics 는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다. (간단히 말하자면 다룰 객체의 타입을 미리 명시해줌으로써 형 변환을 하지 않아도 되게 하는 것)

 

 

 

제네릭스에서는 Reference Type (참조형타입), 간단히 말해 Type 을 의미하는 기호로 'T' 를 사용한다. (어떠한 참조형 타입도 가능하다는 것을 의미) 'T' 외에도 element 의 첫 문자인 'E', key 를 의미하는 'K', value 를 의미하는 'V', number 을 의미하는 'N' 도 사용된다. 이들은 모두 기호의 종류만 다를 뿐 '임의의 참조형 타입' 을 의미한다는 것은 같다. 기존에는 다양한 종류의 타입을 다루는 메서드의 매개변수, 리턴타입으로 Object 타입의 참조변수를 많이 사용했고 그로 인해 형변환이 불가피했지만, Generics 도입 이후에는 Object 타입 대신 원하는 타입을 지정하기만 하면 되어서 코드가 간결해졌다. 

 

 

 

ArrayList class 를 확인해보면 다음과 같이 쓰여있는 것을 확인할 수 있다.

 

 

 

 

Object 타입이 아닌 임의의 타입 E 가 적혀있는 것을 확인할 수 있다. 

 

 

이번에는 HashMap 을 확인해보았다.

 

 

 

 

HashMap 에도 K, V 가 적혀있는 것을 확인할 수 있다.

 

 

 

Generic 을 이용하여 Class 를 아래와 같이 생성해볼 수 있다.

 

 

class GenericTest<E> {
    private E element;

    void set(E element) {
        this.element = element;
    }
    E get() {
        return element;
    }
}
public class Main {
    public static void main(String[] args){
        GenericTest<String> test1 = new GenericTest<String>();
        GenericTest<Integer> test2 = new GenericTest<Integer>();
        test1.set("TEST1");
        test2.set(11);
        System.out.println(test1.get());
        System.out.println(test2.get());
        System.out.println(test1.get().getClass().getName());
        System.out.println(test2.get().getClass().getName());
    }
}

 

 

result

 

 

Generic 을 사용할 때 주의할 점으로, 타입 파라미터로 primitive type 이 올 수 없다는 것이다. (int, double 등)

 

 

 

클래스 내에서 사용하는 객체 타입을 체크하는 것뿐만 아니라, 별도로 메서드에 한정한 Generic 을 사용해볼 수도 있다. 일반적으로 형식은 아래와 같다고 한다.

 

 

public <T> T genericMethod(T o) {	
		...
}
 
[접근 제어자] <제네릭타입> [반환타입] [메소드명]([제네릭타입] [파라미터]) {
		...	
}

 

 

아래와 같이 Generic 메서드를 위 코드에 하나 추가하여 테스트해볼 수 있다.

 

 

    public <T> T genericMethodTest(T t) {
        return t;
    }

 

 

위와 같은 Generic 메서드는 정적 메서드를 선언할 때 유용하다고 한다. 

 

 

 

또, 와일드카드 "?" 를 사용하여 특정 수용범위를 지정해줄 수 있다. 와일드카드는 3 가지 방식으로 사용될 수 있다.

 

 

  •  <? extends T> : 와일드카드의 상한제한. T와 그 자손들만 가능
  • <? super T> : 와일드카드의 하한 제한. T와 그 조상들만 가능
  • <?> : <? extends Object> 와 동일하며, 모든 타입이 가능함.

 

 

 

 

Reference:

https://st-lab.tistory.com/153

자바의 정석