(2024모각소)JAVA - 제네릭과 와일드 카드-1

LEEHYUNJE·2024년 8월 10일
0

아주대학교_모각소!

목록 보기
15/23

계속 대충이해만 하고 넘어갔었는데, 백엔드에서 JWT토큰을 다루니 지식의 공백이 엄청나게 느껴저서 한번 제대로 공부하고 넘어가려고 만들었다.

그리고 자료를 찾으면서 공부하던 도중 정말 완벽하게 설명해주신 분이 계서 이 분의 스토리라인을 활용하여 정리하도록 하겠다.

제네릭

제네릭이 등장하기 이전

제네릭은 JDK 1.5에 등장하였다. 이 제네릭이 존재하기 전에 컬렉션의 요소를 출력하는 메소드는 다음과 같이 구현할 수 있었다.

void printCollection(Collection c) {
    Iterator i = c.iterator();
    for (k = 0; k < c.size(); k++) {
        System.out.println(i.next());
    }
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

c.iterator() : 컬렉션을 반복문을 통해 표현이 가능한 형태(이터레이터 객체)로 반환하는 메서드이다.

하지만 위 Collection의 타입이 무엇인지 알 수 없기 때문에

int sum(Collection c) {
    int sum = 0;
    Iterator i = c.iterator();
    for (k = 0; k < c.size(); k++) {
        sum += Integer.parseInt(i.next());
    }
    return sum;
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

위와 같은 코드에서 Collection이 String 타입의 요소를 가져도 컴파일은 완료되지만, 런타임에서 에러가 발생하는 상황이 나왔다.
이에 타입을 지정하여 컴파일 시점에 안정성을 보장받울 수 있게 하는 방법이 제네릭 방법이다.

제네릭 등장

제네릭이 등장하면서 컬렉션에 타입을 지정할 수 있게 되었고, 이를 통해서 런타임 에러를 줄일 수 있게 되었다.

void sum(Collection<Integer> c) {
    int sum = 0;
    for (Integer e : c) {
        sum += e;
    }
    return sum;
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

하지만 단점이 발생했다. 제네릭은 불공변 이기 때문에 printCollection은 모든 타입의 요소들을 출력할 수 있지만, 제네릭을 사용하게 된다면 모든 타입에서 공통적으로 사용되는 메소드를 만들 방법이 없어졌다.

@Test
void genericTest() {
    List<Integer> list = Arrays.asList(1, 2, 3);
    printCollection(list);   // 컴파일 에러
}

void printCollection(Collection<Object> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

불공변 : A가 B의 하위 타입일 때, T< A > 가 T< B > 의 하위 타입이 아니라면 이것은 불공변이다.
즉 integer은 Object의 하위 타입이지만, Collection<'integer>는 Collection<'Object>의 하위타입이 아니므로, 매개변수로 지정된 객체 c 에 전달 될 수 없다는 소리이다.

그래서 이에 제네릭 등장 이전보다 실용성이 떨어졌기 때문에, 와일드 카드라는 타입이 추가 되었다.

와일드 카드

와일드카드의 등장

제네릭 등장으로 인해 떨어진 실용성을, 모든 타입을 대신할 수 있는 와일드카트 타입을 추가하여 극복했다.

와일드카드는 컴퓨터 프로그래밍에서 ? 와 같이 하나 이상의 문자들을 상징하는 특수 문자를 뜻한다.

이는 여러 타입이 들어올 수 있음을 의미하는데, 이미 만들어진 제네릭 타입을 기반으로 활용할 때 사용된다.

// 제네릭 메서드
public <T> void generitMethod(Box<T> box) {
     System.out.println("T = " + box.get());
 }
 
// 와일드카드를 활용한 일반적인 메서드
public void wildcardMethod(Box<?> box) {
     System.out.println("? = " + box.get());
 }
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

와일드 카드인 ?는 임의의 타입을 나타내며, 정해지지 않은 unknown type으로 타입에 제한이 없어 이를 비제한 와일드카드 타입이라고 한다. 자바에서 모든 객체의 최상위 부모는 Object이므로 다음과 같이 컬렉션을 활용할 수 있게 허용해준것.

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

하지만 요소를 추가하는 경우는 다르다.(위는 요소를 출력하는 예시들) 와일드카드인 ? 타입은 unknown type이므로, 컴파일러가 구체적으로 어떤 타입인지 알 수 없다. 이 컬렉션에 요소를 추가하는 것을 허용하면 integer, String 등 다양한 클래스를 추가할 수 있게되어 안전성을 보장할 수 없으므로, 요소를 추가하는 연산을 허용하지 않는다.

@Test
void genericTest() {
    Collection<?> c = new ArrayList<String>();
    c.add(new Object()); // 컴파일 에러
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

한정적 와일드 카드

java에서는 위와 같은 문제를 해결하고자 한정적 와일드 카드(Bounded Wildcard)를 제공하고 있다.
특정 타입을 기준으로 상한 범위와 하한 범위를 지정하는 방식이며 이를 상한 경계 와일드카드, 하한 경계 와일드 카드로 부른다.
아래 가정을 살펴보겠다.

class MyGrandParent {

}

class MyParent extends MyGrandParent {

}

class MyChild extends MyParent {

}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

상한 경계 와일드 카드

와일드카드 타입에 extends를 사용해서 와일드카드 타입의 최상위 타입을 정의하여 상한 경계를 설정한다.

void printCollection(Collection<? extends MyParent> c) {
    // 컴파일 에러
    for (MyChild e : c) {
        System.out.println(e);
    }

    for (MyParent e : c) {
        System.out.println(e);
    }

    for (MyGrandParent e : c) {
        System.out.println(e);
    }

    for (Object e : c) {
        System.out.println(e);
    }
}
출처: https://mangkyu.tistory.com/241 [MangKyu's Diary:티스토리]

위와 같이 설정해 놓았을때 MyChild 타입으로 꺼내는 경우에는 컴파일 에러가 발생하는 것을 확인할 수 있다.


모각소 후기

오늘은 계속 눈에 성가시던 제네릭과 와일드 카드에 대해서 공부했다. 아직 할 부분이 더 남아있지만, 다음 모각소 만남에서 아예 끝장을 볼 생각이다. 진짜 이제 수강신청도 끝나고, 개강이 남았는데 내가 생각했던 발전이 아직 멀게 느껴진다. 남은 시간동안 팀원들과 같이 열심히 해야겠다.


출처

https://mangkyu.tistory.com/241

profile
현재진행중

0개의 댓글