Почему Guava TypeToken <T>.getRawType() возвращает класс <? super T> вместо класса <T>

Из эффективного Java Second Edition, пункт 28: "Не используйте типы подстановочных знаков в качестве типов возврата. Вместо того, чтобы предоставлять дополнительную гибкость для ваших пользователей, это заставит их использовать подстановочные типы в клиентском коде".

public final Class<? super T> getRawType()

Я только что столкнулся с универсальными подстановочными знаками, чтобы понять последнее предупреждение без предупреждения, которое у меня есть в куске кода, который я пишу, и я не понимаю, почему getRawType() возвращает тип подстановочного знака.

class Base<T>{}
class Child<T> extends Base<T>{}

public <C> void test (TypeToken<? extends Base<C>> token) {
    Class<? extends Base<C>> rawType = (Class<? extends Base<C>>) token.getRawType();
}

Мне нужно отправить token.getRawType(), поскольку он возвращает

Class<? super ? extends Base<C>>

Ответ 1

Что делать, если у вас есть TypeToken<ArrayList<String>>, и вы хотите получить Class<ArrayList> (это необработанный тип). Если он вернет Class<T>, тогда он вернет Class<ArrayList<String>>, который вам не нужен Class<ArrayList>.

Ответ 2

Если общий тип "токена" является классом типа (т.е. если S в

TypeToken<S>

- это класс java.lang.reflect.Type), то TypeToken.getRawType() возвращает необработанный тип, связанный с S. Он должен быть объектом класса, родителем S.

Смотрите исходный код TypeToken.

В некоторых случаях (например, с несколькими ограничениями) реализованная стратегия не будет работать, а тип raw - Ok: исходным типом будет Object.class

См. например MoreTypes:

public static Class<?> getRawType(Type type) {
...
} else if (type instanceof TypeVariable) {
  // we could use the variable bounds, but that'll won't work if there are multiple.
  // having a raw type that more general than necessary is okay  
  return Object.class;

} else {
...
}