Обобщения Java действительно реализованы с помощью стирания типа , поэтому в байт-коде нет информации о типе.
Например, давайте рассмотрим два класса, которые объявляют поле List
, один в общем и другой в неуниверсальном виде:
class NonGeneric {
List list;
}
И
class Generic {
List<String> list;
}
В обоих случаях результирующий байт-код выглядит следующим образом:
Code:
Stack=3, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/util/ArrayList
8: dup
9: invokespecial #3; //Method java/util/ArrayList."<init>":()V
12: putfield #4; //Field list:Ljava/util/List;
15: return
Нет ссылки на тип String
, используемый в ArrayList
или List
. Итак, мы можем видеть, что обобщения действительно реализуются с помощью стирания типов.
Однако, если мы посмотрим на постоянный пул, мы сможем найти разницу.
Неуниверсальный постоянный пул:
Constant pool:
const #1 = Method #6.#15; // java/lang/Object."<init>":()V
const #2 = class #16; // java/util/ArrayList
const #3 = Method #2.#15; // java/util/ArrayList."<init>":()V
const #4 = Field #5.#17; // NonGeneric.list:Ljava/util/List;
const #5 = class #18; // NonGeneric
const #6 = class #19; // java/lang/Object
const #7 = Asciz list;
const #8 = Asciz Ljava/util/List;;
const #9 = Asciz <init>;
const #10 = Asciz ()V;
// snip the rest //
Общий постоянный пул:
Constant pool:
const #1 = Method #6.#17; // java/lang/Object."<init>":()V
const #2 = class #18; // java/util/ArrayList
const #3 = Method #2.#17; // java/util/ArrayList."<init>":()V
const #4 = Field #5.#19; // Generic.list:Ljava/util/List;
const #5 = class #20; // Generic
const #6 = class #21; // java/lang/Object
const #7 = Asciz list;
const #8 = Asciz Ljava/util/List;;
const #9 = Asciz Signature;
const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;;
const #11 = Asciz <init>;
const #12 = Asciz ()V;
// snip the rest//
Как видно, в классе Generic
мы можем видеть, что в пуле констант есть две дополнительные константы, #9
и #10
, в которых упоминается, что List
имеет общий тип String
.
(И с учетом новых знаний, которые я узнал из ответа Криса Джестера-Юнга )
Если посмотреть дальше на разборку файла класса, есть ссылка на константу # 10 прямо перед Code: block
класса Generic
:
java.util.List list;
Signature: length = 0x2
00 0A
Шестнадцатеричное значение 0A
равно 10
в десятичном виде, что относится к константному пулу #10
:
const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;;
Поэтому информация из пула констант используется для указания того, что поле имеет универсальный тип.