Ограниченные параметры Java в общих методах
Я тестировал некоторые вещи с ограниченными параметрами в общих методах, и я обнаружил какое-то странное поведение.
Было бы здорово, если бы кто-нибудь мог объяснить две ошибки в следующем фрагменте кода.
Представьте, что существуют два класса Class1
и Class2
, которые простираются от a BaseClass
. Class2
реализует интерфейс.
В Class1
у меня есть метод, который возвращает экземпляр Class2
следующим образом:
public class Class2 extends BaseClass implements Interface {
@Override
public void method() {
System.out.println("test"); //$NON-NLS-1$
}
}
public class Class1 extends BaseClass {
public <T extends BaseClass & Interface> T getTwo() {
return new Class2();
// Error: Type mismatch: cannot convert from Class2 to T
}
public static void main(String[] args) {
Interface two = new Class1().getTwo();
// Error: Bound mismatch: The generic method getTwo() of type Class1 is
// not applicable for the arguments (). The inferred type Interface is
// not a valid substitute for the bounded parameter <T extends BaseClass
// & Interface>
System.out.println(two);
}
}
Ответы
Ответ 1
Первая ошибка компиляции возникает, поскольку параметры типа, объявленные методами, определяются вызывающим, а не реализация метода. То есть, учитывая
class Class3 extends BaseClass implements Interface { ... }
вызывающий может написать
Class3 c3 = new Class1().<Class3>getTwo();
но реализация метода возвращает a Class2
, который не является подтипом T
= Class3
.
Вторая ошибка компиляции возникает из-за того, что параметры типа, которые явно не указаны вызывающим, выводятся из аргументов метода и типу переменной, которой присвоено значение метода. Этот вывод терпит неудачу. Обычным обходным решением, рекомендованным спецификацией языка Java, является указание параметров типа явно в таких случаях (вывод типа предназначен для удобства для простых случаев, он не предназначен для охвата всех случаев).
Как правильно объявить этот параметр типа, мне нужно знать, что вы пытаетесь выполнить с этими объявлениями.
Ответ 2
Зачем использовать generics для метода getTwo
, когда вы знаете его Class2
? Просто сделайте следующее:
public Class2 getTwo() {
return new Class2();
}
Если вы переопределяете метод public <T extends BaseClass & Interface> T getTwo()
, компилятор позволит вам объявить ваш impl как public Class2 getTwo()
, когда ваш T
для вашего impl <<21 >