JavaBookStudy / JavaBook

책읽기 스터디
https://javabookstudy.github.io/
Apache License 2.0
19 stars 2 forks source link

[Effective Java] Item 28. 제네릭은 런타임 시간에서 타입 안전하지 않다?? #16

Closed taxol1203 closed 3 years ago

taxol1203 commented 3 years ago

이 item의 마지막, 핵심 정리에는 다음과 같은 내용이 있습니다.
배열은 런타임에는 타입 안전한 반면, 컴파일 타임에는 그렇지 않다. 제네릭은 그 반대다.
이 말은 즉슨, 제네릭은 런타임에서 타입 안전하지 않다고 합니다.

그런데,165p.에서 3번째 문단에서는 런타임에 ClassCastException 발생을 막아준다는 제네릭 타입 시스템 취지에 어긋난다. 라고 되어있습니다.

무언가 두 문장이 모순되는 것 같은데, 제가 추측한 바로는
제네릭이 컴파일 타임에 ClassCastException을 미리 알아채고 이후 런타임에서는 타입 정보가 소거된다고 하니, 런타임에서 코드28-3처럼 ClassCastException가 발생 할 수도 있으니 런타임 타입 안전 x인걸까요?

사실 저 추측도 모순이 있는 것 같습니다. 번쩍이는 의견 부탁드리겠습니다. 👀

kjsu0209 commented 3 years ago

제네릭이 런타임에 안전하지 않은 이유가 제네릭 배열을 생성할 때 문제가 생겨서 그렇습니다. 배열을 생성하면 레퍼런스가 다음과 같이 이어집니다. (레퍼런스를 포인터라고 부르겠습니다ㅎㅎ)

배열을 가리키는 포인터 -> 원소 객체를 가리키는 포인터 -> 원소 객체 데이터

일반적으로 제네릭 객체를 만들면 포인터를 하나만 쓰고, 배열을 만들면 포인터가 2개가 됩니다. 포인터가 하나일 경우 컴파일러가 바로 확인이 가능하지만 포인터가 2개일 경우 배열을 가리키는 포인터원소 객체를 가리키는 포인터를 각각 따로 컴파일러가 검사합니다. 컴파일 시점에서는 당장 검사할 수 있는 것만 체크하는 겁니다. 그래서 코드 28-3이 컴파일 에러 없이 작동되는 것이라고 생각됩니다.

지금은 이 정도까지 생각나는데 좀 더 공부해 보고 다른 아이디어 생기면 코멘트 추가할게요 :smile: