2010-10-26 54 views
5

这里不同的预期返回类型的一些代码我工作的一个例子:Java泛型 - 比实际

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! 

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

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

我无法理解为什么富的声明中列出的参数化类型已去为了使返回类型正确。

任何想法?

+0

'T扩展Enum &FooType'是什么? T必须是枚举并扩展FooType,但是不能扩展枚举! – 2010-10-26 13:37:19

+0

使用泛型时,关键字“extends”用于描述实现的接口。 FooType也是一个接口,你仍然可以使用extends关键字。 – Nick 2010-10-26 15:01:32

回答

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的类型到您的列表。

+0

这实际上是非常有意义的,失效是所有事情都会发生重大变化的地方,您的建议可以像广告中那样工作。 – Nick 2010-10-26 15:08:28

0

因为您声明makerFooMaker<?>。如果你知道什么具体的TAwesomeFooMaker返回,你为什么不宣称它是AwesomeFooMaker的类型?

+0

我会编辑我的代码smidge。我其实不知道我会得到哪个FooMaker。 – Nick 2010-10-26 12:57:19

+2

这并不重要。通过将类型参数声明为'''''''''''''''''''''''''''''''''''''''''''''我不知道会返回什么样的类型,编译器本质上就好像任何与类型参数相关的方法现在都是'?',即使它是'List ' 。你不能使用'FooMaker'?extends FooType> maker'? – 2010-10-26 13:01:37

+0

接口的返回类型是List >,我的声明我说它可以是任何类型T.即使我声明FooMaker <?extends FooType>我还是得到了一个类似的错误,我试图理解为什么Foo参数化类型被忽略 – Nick 2010-10-26 13:11:25

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! 
+0

我选择了另一个人回答这个问题,因为他包含了解决我的限制的方法,但是我很欣赏你的输入关于为什么它不能按我期望的那样工作+1 – Nick 2010-10-26 15:09:15