Я собираюсь создать фабрику, которая создает объекты определенного типа T, который расширяет определенный класс A и другой интерфейс I. Однако T не должен быть известен. Вот минимальные декларации:
public class A { }
public interface I { }
Это заводской метод:
public class F {
public static <T extends A & I> T newThing() { /*...*/ }
}
Это компилируется все нормально.
Когда я пытаюсь использовать этот метод, отлично работает следующее:
A $a = F.newThing();
... пока это не так:
I $i = F.newThing();
Компилятор жалуется:
Несоответствие границ: универсальный метод newThing() типа F неприменим для аргументов(). Выведенный тип I&A не является допустимой заменой ограниченного параметра
Я не могу понять, почему. Четко сказано, что «newThing возвращает что-то определенного типа T, который расширяет класс A и реализует интерфейс I». При присвоении A все работает (поскольку T расширяет A), но при присвоении I нет (из-за чего?, ясно, что возвращаемая вещь является одновременно A и и я)
Также: при возврате объекта, скажем, B типа class B extends A implements I
, мне нужно привести его к возвращаемому типу T, хотя B соответствует границам:
<T extends A & I> T newThing() {
return (T) new B();
}
Однако компилятор не выдает никаких предупреждений, таких как UncheckedCast и тому подобное.
Таким образом, мой вопрос:
- Что здесь происходит не так?
- Можно ли легко добиться желаемого поведения (т. е. присвоить значение переменной статического типа A или I), как это делается при решении проблемы возвращаемого типа путем приведения в фабричном методе?
- Почему назначение А работает, а I нет?
--
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());
}
}
A $a = F.newThing();
не работает. Вы уверены, что не объявилиclass A implements I { }
? - person Andrew Spencer   schedule 22.03.2012A $a = F.newThing();
компилируется, но выдаетClassCastException
во время выполнения, еслиB
не расширяетA
. Это даже компилируется с<T extends I>
. - person Thomas   schedule 22.03.2012