Java часто может вызывать обобщения на основе аргументов (и даже типа возврата, в отличие от, например, С#).
Пример: у меня есть общий класс Pair<T1, T2>
, который просто хранит пару значений и может использоваться следующим образом:
Pair<String, String> pair = Pair.of("Hello", "World");
Метод of
выглядит так:
public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) {
return new Pair<T1, T2>(first, second);
}
Очень приятно. Однако это больше не работает для следующего прецедента, для которого требуются подстановочные знаки:
Pair<Class<?>, String> pair = Pair.of((Class<?>) List.class, "hello");
(Обратите внимание на явное приведение, чтобы сделать List.class
правильный тип.)
Код не работает со следующей ошибкой (предоставленной Eclipse):
Несоответствие типов: невозможно преобразовать из
TestClass.Pair<Class<capture#1-of ?>,String>
вTestClass.Pair<Class<?>,String>
Однако явно вызов конструктора по-прежнему работает так, как ожидалось:
Pair<Class<?>, String> pair =
new Pair<Class<?>, String>((Class<?>) List.class, "hello");
Может кто-нибудь объяснить это поведение? Это по дизайну? Это нужно? Я делаю что-то неправильно или я наткнулся на недостаток в дизайне/ошибке в компиляторе?
Дикая догадка: "захват # 1-из?" как-то кажется, подразумевает, что подстановочный знак заполняется компилятором "на лету", создавая тип a Class<List>
и, таким образом, не выполняет преобразование (от Pair<Class<?>, String>
до Pair<Class<List>, String>
). Это правильно? Есть ли способ обойти это?
Для полноты использования здесь приведен упрощенный вариант класса Pair
:
public final class Pair<T1, T2> {
public final T1 first;
public final T2 second;
public Pair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) {
return new Pair<T1, T2>(first, second);
}
}