glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-007] ParameterizedType에 대한 보충 설명 #154

Closed glenn-syj closed 1 month ago

glenn-syj commented 2 months ago

based on: #147 by @undeadtimo

들어가며

이종 타입 컨테이너는 꽤 어려워서, 누구든간에 앞으로도 다시 공부해 볼 필요가 있겠는데요. 저는 ParameterizedType()이 어떻게 작동하는지 와닿지 않아, 따로 공부를 좀 해보았습니다.

getGenericSuperclass와 ParameterizedType

ParamterizedType은 제네릭 타입이 Collection<E>와 같은 방식으로 제공되는 것과 달리, Collection<String>과 같이 파라미터화된 타입 정보를 제공하는데 쓰입니다. 그런데 이는 당연하게도, 리플렉션을 통해서 제공되고요. 공식문서에서는 파라미터화된 타입 p가 생성될 때, 제네릭 타입 선언이 해석되고, 타입 인자들이 재귀적으로 생성된다고 밝히고 있습니다.

여기에서 재귀적으로 생성된다는 것은, 타입 인자가 복잡하게 중첩될 수 있다는 점을 염두에 둔다고 생각해볼 수 있겠습니다. 예를 들어서, Map<String, List<Integer>>에 해당하는 인스턴스가 있다고 가정해봅시다. 여기에 대해서는 우선적으로 String과 List가 인자가 됩니다. 이어서 List 역시 제네릭의 일종으로, Integer를 인자로 가집니다.

ParameterizedType 클래스에는 getActualTypeArguments(), getOwnerType(), getRawType()이라는 멤버 메서드가 있습니다. getActualTypeArguments는 해당 타입의 실제 타입을 나타내는 Type 객체 배열을 반환합니다. getRawType()은 해당 타입을 선언한 클래스나 인터페이스를 나타내는 Type 객체를 반환합니다. getOwnerType()은 해당 타입이 상속하고 있는 (a member of) 타입을 반환합니다. 만약 탑-레벨 타입이라면 null을 반환한다고 합니다.

Map<String, List>의 예시로 다시 돌아가보겠습니다.

  1. getActualTypeArguments()

해당 메서드를 호출하면, 반환되는 객체 배열은 String에 대한 클래스와 List에 대한 클래스 Type 객체들로 이루어져 있겠습니다. 만약 해당 배열의 1번째 인덱스에 위치한 List에서 getActualTypeArguements()를 다시 호출한다면, Integer 클래스에 대한 Type 객체를 반환하겠습니다.

  1. getOnwerType()

해당 메서드를 호출하면, null이 반환될 것입니다. Map은 그 자체로 탑-레벨 타입이니까요.

  1. getRawType()

해당 메서드를 호출하면, Map에 대한 클래스 Type 객체가 반환되겠습니다.

나가며

간단하게 ParameterizedType 클래스에 대한 내용을 살펴보았는데요. 사실 개발 과정에서 제네릭과 이종 타입 컨테이너를 직접 설계하고 사용해보지 않는다면, 와닿기 어려울 수 있을 것 같습니다. 한 번 쯤 이득이 된다면, 이 모두를 직접 프로젝트에서 사용해보고 싶네요!

References

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/ParameterizedType.html https://stackoverflow.com/questions/20865767/how-to-get-parameterized-type

undeadtimo commented 2 months ago

그동안 ParameterizedType을 볼 때마다 제대로 알고 있지 않았기 때문에, 연과되는 다른 개념들에 대한 이해도 어려웠지만, glenn-syj님께서 정리해주신 덕분에 ParameterizedType에 대해 이해할 수 있게 되었습니다.

앞으로 프로젝트에서 타입 안정성을 체크할 때, ParameterrizedType 클래스의 메서드를 사용해볼 수 있을 것 같습니다.

예를들어, 사용자로부터 받은 입력 데이터의 타입을 체크하는 경우가 될 수도 있겠군요.

훌륭한 글을 작성해주신 점 다시금 감사드립니다.