[Java] 자바의 제너릭은 반쪽짜리다.
자바의 제너릭 시스템에는 이상한 제한이 있다.
ArrayList
왜일까? 그건 자바가 이상한 방식으로 땜빵치듯이 Generic을 구현해놨기 때문이다.
대부분의 Generic 시스템 (우리가 기대하는 것)
원래라면 제너릭 시스템들은 컴파일 단계에서 모든 치환을 완료하기를 기대한다.
C++이나 Rust, C# 등의 대부분 언어들이 그렇게 동작한다.
예를 들어, C++에서는 다음과 같이 제너릭 타입을 정의하곤 한다.
template <class T>
class ArrayList
{
T* array;
}
그리고 다음과 같이 제너릭 구체화를 시도하면
ArrayList<int>
컴파일러가 제너릭 템플릿을 기반으로, int를 채워넣은 "사본"을 생성한다.
class ArrayList_int
{
int* array;
}
이게 보통이다.
Java의 Generic 시스템
엄밀하게 말하면 JVM은 제너릭을 지원하지 않는다.
그저 Java 컴파일러에 의해서 치환이 될 뿐이다.
근데 Java는 매우 신기한 방법으로 제너릭 치환을 처리한다.
아래와 같은 제너릭 정의가 있고
class ArrayList<T>
{
T[] array;
}
구체화를 한다면
var list = new ArrayList<Integer>();
var first = list.get(0);
자바는 T를 Integer로 바꾸는게 아니라, 무작정 Object로 바꿔버린다!
class ArrayList
{
Object[] array;
}
그리고 런타임에 Integer로 캐스팅을 해버리는 것이다.
var list = new ArrayList();
var first = (Integer) list.get(0);
그래서 사실 그냥 Object 버전의 컬렉션을 쓰는 것에 비해 성능상의 이점은 없다고 할 수 있겠다.
어쨌든 제너릭처럼 동작하고, 사용에 큰 문제는 없다.
다만 리플렉션을 적용할때 꼬일 수 있는 상황이 있을 수 있고, 시스템 자체에 일관성이 떨어지는 게 단점이다.
단언은 못하겠지만 아마 최적화도 좀 구릴 것이고...
참조
https://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens