[자바/java]제너릭과 와일드카드 - <? Extends E> (generic/wildcards)
안녕하세요. 신기한 연구소 개발자 티보이입니다.
자바 개발을 하다 보면 배열, Collection 등을 사용하게 됩니다.
다양한 타입을 지원하기 위해 제너릭(generic)을 사용하는데요.
그중 와일드카드(wildcards)를 사용하는데 처음 사용하거나 또는 확실히 이해가 필요한 개발자를 위해 한 번 포스팅해봅니다.
확실히 이해하고 사용한다면 많은 도움이 될 거예요.
렛츠 고~
제너릭을 사용하는 이유는
타입을 미리 지정해서 캐스팅을 사용하지 않아 좀 더 명확하게 사용할 수 있도록 해줍니다.
제너릭(generic)을 사용한 코드를 확인해보겠습니다.
1
2
3
4
5
6
7
8
9
|
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
|
cs |
이 코드는 <Object>라는 타입을 지정하고 있습니다.
이렇게 <Object>로 타입을 지정하는 것을 제너릭이라고 합니다.
그런데 여기서 문제가 좀 있습니다.
혹시 해당 코드를 모든 Collection 타입을 받기 위해 만든 거라면 오류가 발생합니다.
제너릭(generic)은 지정한 타입만 받기 때문입니다.
Object가 최상위 클래스이기에 다 받을 수 있다고 잘못 이해한 코드입니다.
Collection<Object>로 선언하면 모든 Collection 타입 모두를 허용할 수 있다는 것이 아니라는 겁니다.
와일드카드 “?”를 사용해서 아직 알려지지 않은 혹은 미정의 된 Collection 타입이라는 의미에서 Collection<?>를 사용하면 해결됩니다.
1
2
3
4
5
6
7
8
9
|
void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
|
cs |
이렇게 사용하면 Collection의 다양한 타입을 사용할 수 있게 됩니다.
하지만 위 코드도 또 다른 문제가 있습니다.
말했듯이 Collection<?>로 와일드카드를 사용하면 Collection 타입은 안전하게 사용할 수 있지만 임의의 객체를 다 받을 수는 없습니다.
아래의 예제를 보세요.
1
2
3
4
5
|
Collection<?> c = new ArrayList<String>();
c.add(new Object()); //임의의 객체
|
cs |
첫 번째줄은 문제가 없습니다.
아마 객체 c를 Collection<?>로 해서 다양한 타입을 지원하고 싶은 마음에 지정한 듯 보이는데 막상 인스턴스화 하는 부분은 ArrayList<String>으로 지정했습니다.
그래서 ArrayList가 아니거나 또는 ArrayList라도 String 타입이 아니면 오류가 납니다.
두 번째라인을 보면 c의 타입을 Collection<?>로 했기에 new Object() 객체를 add 하면 다 받을 수 있어 보이지만 사실은 오류가 발생합니다.
오류는 String 타입으로 캐스팅하라고 나올 겁니다.
확실히 타입을 정해서 사용한다면 와일드카드 “?”를 사용해도 무방하겠지요?
<? extends E>
혹시 이것을 왜? 어떻게 사용하는지 궁금하시나요?
이 제너릭(generic)은 개발의 다양성을 위한 한 기능이지 않을까 생각해봅니다.
와일드카드 “?”는 설명 했으니 아시겠죠? 지정되지 않은 객체를 받을 수 있다는 의미입니다.
그럼 extends E 는 왜 있을까요?
E는 elements의 약자로 보시면 됩니다. 꼭 E 그대로 사용하는게 아닙니다.
Extends는 상속 의미 그대로입니다. 지정되지 않은 객체 "?" 가 E를 상속받았다는 의미예요.
예를 들어볼께요.
게임 개발을 하는데 유닛 추상클래스(abstract clsss Units)가 있습니다.
그리고 인간(class Human extends Units),
요정(class Fairy),
오크(class Oak)로 구성된 유닛들이 있습니다.
이 세개의 클래스는 유닛 추상클래스를 상속받습니다.
각 유닛들은 게임판에 객체를 생성해서 이미지로 표현해야 합니다.
게임판이라는 클래스가 있고 그 안에는 객체를 이미지로 만드는 메서드가 있습니다.
각 유닛들 인간, 요정, 오크를 모두 그려야 하는 경우 각각 메서드를 구성하고 호출하게 되면 소스도 중복되고 비효율적인 소스가 됩니다.
이런 경우 객체들을 List에 담은 뒤 List 객체로 넘겨주면 되는데…
문제는 List 내에 인간, 요정, 오크 등 다양한 타입이 존재하게 됩니다.
위에서 사용한 제너릭(generic)과 와일드카드(wildcards)로 메서드를 만들어 봤습니다.
1
2
3
4
5
6
7
8
9
|
Public void showAllUnit(List<Units> units){
For (Units u: units) {
u.makeImg(this);
}
}
|
cs |
이렇게 되면 위에서 말했듯 List내에서 <Units> 타입만 찾게 됩니다.
즉, Human, Fairy, Oak는 찾을 수 없습니다.
이런 경우 사용할 수 있는 제너릭(generic)이 <? Extends E> 입니다.
1
2
3
4
5
|
Public void showAllUnit(List<? extends Units> units){
}
|
cs |
이렇게 되면 List에서 와일드카드(wildcards) ? 의 타입을 찾아야 하는데 바로 Units 클래스를 상속받은 Human, Fairy, Oak를 받을 수 있게 됩니다.
이해가 되셨나요?
이제 제너릭(generic)과 와일드카드(wildcards) 그리고 <? Extends E>사용법을 알게 되었으니 개발에 잘 활용하시길 바랍니다.
즐 코딩하세요~
'Software > Java' 카테고리의 다른 글
[자바/java]List - ArrayList 이해하고 사용해 보기. - Collection, 리스트 (0) | 2020.05.13 |
---|---|
[자바/java]컬렉션에서 Set 은 어떻게 사용할까요? Collection/Set (0) | 2020.05.12 |
[자바]Random 클래스로 난수를 만들어 보기 - long seed, java.util.Random; (0) | 2020.05.08 |
[자바]추상클래스 vs. 인터페이스 사용방법. Abstract Class vs. Interface (0) | 2020.05.05 |
[자바]StringBuffer vs. String 메모리 관리하기. (0) | 2020.05.03 |