Java Generics - 预期的返回类型与实际不同

时间:2010-10-26 12:51:20

标签: java generics

以下是我正在处理的一些代码示例:

public interface FooMaker<T extends Enum<T> & FooType>
{
      public List<Foo<T>> getFoos(String bar);
}

让我们进一步假设FooMaker会有许多不同的具体实现。所以我写了一些代码来使用FooMakers。

FooMaker<?> maker = Foos.getRandomMaker();
List<Foo<?>> fooList = maker.getFoos("bar");  //error here!

第二行代码导致问题,eclipse告诉我代码应该是:

FooMaker<?> maker = Foos.getRandomMaker();
List<?> fooList = maker.getFoos("bar");

我无法理解为什么Foo声明作为List中的参数化类型必须消失才能使返回类型正确。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

通常的:

class Bar {}
class Baz {}

FooMaker<?> maker = new FooMaker<Bar>();
List<Foo<?>> fooList = maker.getFoos("bar");  //error here!
fooList.add(new Foo<Baz>());                  //cock-up here!

答案 1 :(得分:1)

请改为尝试:

List<? extends Foo<? extends Enum<?>>> fooList = maker.getFoos("bar");

问题是,如果允许这样做:

List<Foo<?>> fooList = maker.getFoos("bar");

然后,通过扩展,你也可以逃脱这个:

Foo<?> foo1 = new Foo<String>();
Foo<?> foo2 = new Foo<Integer>();
fooList.add(foo1);
fooList.add(foo2);

哪会使返回列表的通用合约无效。

为了防止这种情况,java编译器强制返回类型是基于通配符的,这意味着Foo可以用作返回类型(将元素拉出列表),但是你将无法添加基于通配符的Foo键入您的列表。

答案 2 :(得分:0)

因为您将maker声明为FooMaker<?>。如果您知道具体的AwesomeFooMaker T返回什么,为什么不将其声明为AwesomeFooMaker的类型?

相关问题