«… почему эта ошибка? …«
Ошибка, которую javac
сообщает о вашем исходном коде, дает вам эту причину :
...GenericBug.java:14: error: type argument T#1 is not within bounds of type-variable T#2
return new FooManager<T>(type); //Error: Bound mismatch
^
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>createFooManager(Class<T#1>)
T#2 extends Foo declared in class FooManager
1 error
T#1 is not within bounds of type-variable T#2
потому что:
<T> ObjectManager<T> createFooManager(...)
означает, что вы определили T
( aka T#1
) как имеющий без границ. - Параметр типа
T
( aka T#2
) из FooManager<T extends Foo>
определяется с помощью границ extends Foo
. А метод generi c T
не расширяет Foo
, как того требует класс generi c. Значит, это за пределами .
«… как это исправить …»
Ваш оригинал Foo.class.isAssignableFrom(type)
подход кажется мне не очень объектно-ориентированным. Итак, в основном, Я исправил это следующим образом .
...
private static <T> ObjectManager<T> createObjectManager(Class<T> type) {
return new ObjectManager<>(type);
}
private static <S extends Foo> ObjectManager<S> createFooManager(Class<S> type) {
return new FooManager<>(type);
}
...
Не очевидно, каков ваш вариант использования IRL. Поэтому мне пришлось сделать некоторые предположения. Как я и предполагал, вы, скорее всего, будете использовать это с более специализированными реализациями Foo
. Поэтому я ввел FooJr
, чтобы продемонстрировать, как решение будет справляться с этим:
ObjectManager<? extends Foo> objectManager1 = createFooManager(Foo.class);
System.out.println(objectManager1.getDescription());
ObjectManager<?> objectManager2 = createObjectManager(Object.class);
System.out.println(objectManager2.getDescription());
objectManager1 = createFooManager(FooJr.class);
System.out.println(objectManager1.getDescription());
objectManager2 = createObjectManager(FooJr.class);
System.out.println(objectManager2.getDescription());
Сказать, что одно решение - « лучше » или « хуже «чем другой - субъективно; возможно, дело личного вкуса. Но с объективностью ( каламбур ) можно сказать, что одно решение может быть более объектно-ориентированным , чем другое. Некоторые решения определенно более безопасны, чем другие.
«… без предупреждения? …»
Это решение является более безопасным по типу. Запустите его с -Xlint:unchecked
. Компилятор не выдает непроверенных предупреждений. И это без необходимости в каких-либо @SuppressWarnings(...)
.
«… почему Eclipse предоставляет решение, которое не компилируется? …»
Eclipse только представил вам свое наилучшее предположение в том, что, по его мнению, можно исправить для проблемы. В природе IDE есть пропуск некоторых вещей, которые javac
или JLS абсолютно не допускают.