Я собираюсь создать factory, который создает объекты определенного типа T, который расширяет некоторый класс A и другой интерфейс I. Однако T не должно быть известно. Вот минимальные объявления:
public class A { }
public interface I { }
Это метод factory:
public class F {
public static <T extends A & I> T newThing() { /*...*/ }
}
Это компилирует все отлично.
Когда я пытаюсь использовать метод, следующее работает нормально:
A $a = F.newThing();
... пока это не так:
I $i = F.newThing();
Компилятор жалуется:
Связанное несоответствие: общий метод newThing() типа F не применим для аргументов(). Выведенный тип я & A не является допустимым заменой ограниченного параметра
Я не понимаю, почему. Ясно, что "newThing возвращает что-то определенного типа T, которое расширяет класс A и реализует интерфейс I". При назначении A все работает (так как T расширяет A), но присваивание я не делает (из-за чего?, ясно, что возвращаемая вещь является как A, так и I)
Также: при возврате объекта, скажем B типа class B extends A implements I
, мне нужно передать его в тип возврата T, хотя B соответствует границам:
<T extends A & I> T newThing() {
return (T) new B();
}
Однако компилятор не выдает никаких предупреждений, таких как UncheckedCast или т.п.
Таким образом, мой вопрос:
- Что здесь происходит?
- Легко ли достичь желаемого поведения (т.е. присваивания переменной статического типа A или I), как и при решении проблемы возвращаемого типа путем литья в методе factory?
- Почему назначение A работает, а для меня нет?
-
EDIT: Здесь полный фрагмент кода, который полностью работает с использованием Eclipse 3.7, проект, созданный для JDK 6:
public class F {
public static class A { }
public static interface I { }
private static class B extends A implements I { }
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
}
}
EDIT: Вот полный пример с методами и вызовами, которые работают во время выполнения:
public class F {
public static class A {
int methodA() {
return 7;
}
}
public static interface I {
int methodI();
}
private static class B extends A implements I {
public int methodI() {
return 12;
}
}
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
System.out.println($a.methodA());
}
}