참고 문서
외부링크
Wildcard에 대한 java documentation : https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Generic & Subtyping : http://docs.oracle.com/javase/tutorial/extra/generics/subtype.html
개요
작년에 wildcard에 대해 스터디한 내용이 있었다는 사실에 한 번 개깜놀
까맣게 잊고 있었다는 사실에 두 번 개깜놀
wildcard 와 type parameter 간의 가장 중요한 차이점은 code statement 내에 선언된 param이 재참조되는지 여부이다.
재참조 되면 type parameter 써야 하고, 재참조 안되고 귀찮으면 그냥 ? 쓴다.
Wildcard ?
java syntax에는 ? 라는 것이 있다. generic type parameter로 쓰인다. (e.g. ArrayList<?>)
Long story short…
generic type parameter 를 명확히 결정하지 않은 채로 두기 위한(=unknown type) syntax
Generic 의 type parameter 는 polymorphism 을 지원하지 않는다.
generic에서는 type prarmeter 에 대하여 polymorphism 을 지원하지 않는다. 다음 예제를 보자.
Generic
Collection<String> foo = new ArrayList<String>; Collection<Object> refFoo = foo; //compile error!! refFoo.add(new Object()); String bar = foo.get(0); //만일 line2 가 error가 아니었다면, bar 에 Object 를 할당하는 참사가 발생하게 된다.
얼핏 생각하면 ArrayList<Dog> 을 List<Animal> 으로 받을 수 있을 것 같지만, 상기 예제와 같은 문제를 막기 위해 Generic 의 type parameter 는 문법적으로 subtype 변환을 허용하지 않는다.
혼란을 막기 위한 제한이지만, type 체크가 엄격하면 유연한 사용이 힘들다. Wildcard 는 이런 상황을 해결하기 위해 고안된 문법이다.
private void foo(Collection<?> c) { for (Object iter : c) System.out.println(iter); } List<String> bar = new ArrayList<String>; bar.add("hello"); foo(bar); //okay!!
case Obect
private void foo(Collection<Object> c) { for (Object iter : c) System.out.println(iter); } List<String> bar = new ArrayList<String>; bar.add("hello"); foo(bar); //compile error!!
Wildcard 사용시 주의할 점
bounded wildcard
spring에서 용례
spring-context 의 SimpleApplicationEventMulticaster.multicastEvent()
정확한 type을 알 수 없는 ApplicationListner<T>를 이터레이션 하기 위하여 wildcard가 사용되었다.
SimpleApplicationEventMulticaster.java
@Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}