Вы можете определить тип любого объекта в genericField
во время выполнения, но вы не можете определить разницу между TestClass<X>
и TestClass<Y>
во время выполнения без рассмотрения некоторых членов, которые вы знаете, случается, сдерживаются общего типа. То есть вы не можете определить параметр типа TestClass<...>
с учетом экземпляра TestClass
.
Ваш код отображает тип значения genericField
«s, не параметризованный тип экземпляра TestClass
. Попробуйте распечатать this.getClass()
, и вы увидите, что он идентичен в обоих случаях.
Что вы «пропустили»: это, по-видимому, неправильное соединение между фактом, что genericField
сам содержит объект (с типом) и тот факт, что TestClass
имеет параметр типового типа. Вы сбиваете с толку возможность определить тип значения genericField
s с возможностью определения параметра типа, указанного в TestClass
. То есть, в то время как вы можете определить, какой параметр типа был основан на , ваш знал, что genericField
- T
, это не то же самое, что напрямую определить, что T
было, что невозможно.
Другой способ смотреть на предыдущем пункте, чтобы рассмотреть эти вопросы:
Если TestClass
не было членов типа T
то нет никакого другого пути вы могли бы извлечь T
. Ваш код только «определяет», что T
был основан на ваших личных знаниях, что genericField
был объявлен как один и тот же тип (и, следовательно, объект в нем должен быть такого типа, и поэтому вы можете заключить, что общий параметр, вероятно, тип или некоторый супертип).
Если вы не использовали генерики, и genericField
был просто Object
, вы все еще быть в состоянии определить тип объекта в genericField
. То есть его тип является «независимым» от общего типа, за исключением случаев, когда вы используете generics, компилятор помещает ограничение на тип. Это все еще просто произвольный объект после компиляции, независимо от того, используете ли вы дженерики (которые на самом деле просто удобны, поскольку вы могли бы сделать все это без дженериков и просто использовать Object
и множество отливок).
Рассмотрим также возможность TestClass<Base>
, где genericField
отводилась Derived
. Ваш код правильно показал бы, что genericField
был Derived
, но вы не знаете, что параметр типа был Base
по сравнению с Derived
, поскольку информация была удалена.
Кроме того, таранить выше точки дома еще дальше:
TestClass<String> genericString = new TestClass<String>("Hello");
TestClass<?> kludge = genericString;
TestClass<Long> genericLongButNotReally = (TestClass<Long>)kludge;
genericLongButNotReally.printTypeInfo();
Выдает Информация для String
(вот почему эти предупреждения «бесконтрольно преобразования» даны, чтобы предотвратить странные вещи, как это), не заботясь о том, что genericLongButNotReally
был указан с параметром типа Long
. Клад необходим, чтобы обойти хорошую защиту, которую предлагает компилятор, когда вы используете общие типы; но во время выполнения все равно.
Очень ясно; также стоит отметить, что печать 'this.getClass()' в 'printTypeInfo()' даст одинаковые результаты для обоих тестовых примеров, что поможет выделить разницу между способностью определять тип значения «genericField» и способностью для определения параметра типа экземпляра 'TestClass'. –