编辑:在这里还有另一个皱纹,我错过了,结果发挥了重大作用。 doAnotherThing
的方法签名取代以下内容:
<T extends Bar> T doAnotherThing(List<Foo<T>> foo) {
return foo.get(0).doSomething();
}
忽略它是List
这一事实,只需注意List
是通用类/接口这一事实。我正在调用这样的方法:
doAnotherThing(new ArrayList<FooImpl>);
所以,我有一个类和接口定义如下:
abstract class Bar {
// some neat stuff
}
class BarImpl extends Bar {
// some cool stuff
}
interface Foo<T extends Bar> {
T doSomething();
}
class FooImpl implements Foo<BarImpl> {
BarImpl doSomething() {
// Does something awesome
}
}
这一切都很好,花花公子,效果很好。
现在,我有一个像这样的方法:
<T extends Bar> T doAnotherThing(List<Foo<T>> foo) {
return foo.get(0).doSomething();
}
此方法是完全不同类中的通用方法,不属于上述链的一部分。
但是,当我尝试以下列方式使用此方法时,我收到错误消息,说明类型不匹配:
doAnotherThing(new FooImpl());
FooImpl
实现了Foo<T>
,所以我看不出这是怎么回事?也许我误会了什么?感谢
答案 0 :(得分:3)
答案已更改,以反映有问题的澄清
顺应错误(类型不匹配)实际上是完全正确的。请注意,方法定义表示参数为List<Foo<T>>
。这意味着该列表可以包含任何 Foo<T>
,并且该方法甚至必须能够添加任何实现Foo<T>
的对象。当你给它List<FooImpl>
时,情况并非如此,因为只允许包含FooImpl
的实例。这有效:
doAnotherThing(new ArrayList<Foo<BarImpl>>());
混合泛型和多态会很快导致非常复杂的场景,因此应该谨慎地进行。
答案 1 :(得分:2)
适合我。我怀疑造成错误的是什么,它不在你上面的版本中。下面的代码(所有文件,FooBarBaz.java
)是否为您编译?我必须对您的代码进行的唯一更改是将FooImpl.doSomething()
公开。 (哦,让它返回一些东西。:)
)
public class FooBarBaz {
<T extends Bar> T doAnotherThing(Foo<T> foo) {
return foo.doSomething();
}
public static void main(String[] args) {
new FooBarBaz().doAnotherThing(new FooImpl());
}
}
abstract class Bar {
// some neat stuff
}
class BarImpl extends Bar {
// some cool stuff
}
interface Foo<T extends Bar> {
T doSomething();
}
class FooImpl implements Foo<BarImpl> {
public BarImpl doSomething() {
return null;
}
}
使用IDEA 9,Mac OS 10.6.5上的JDK 1.6,可以正常使用。
答案 2 :(得分:1)
让我们假设BarImpl extends Bar
,我相信你从一开始就意味着。
增强的Foo
界面如何?
是吗:
interface Foo<T extends Bar> {
T doSomething();
T doAnotherThing(Foo<T> foo);
}
在这种情况下,一切都可以使用以下内容:
class FooImpl implements Foo<BarImpl> {
public BarImpl doSomething() {
return null;
}
public BarImpl doAnotherThing(Foo<BarImpl> foo) {
return null;
}
}
现在,如果您另外定义它可能会出现问题:
interface Foo<T extends Bar> {
T doSomething();
<T extends Bar> T doAnotherThing(Foo<T> foo);
}
因为这种定义doAnotherThing
的方法引入了另一个泛型参数。令人困惑的是接口的参数和方法中的一个共享名称,即T
。
(顺便说一下,我很惊讶地发现Java允许这种令人困惑的名字冲突)
最后一个定义可以替换为:
interface Foo<T extends Bar> {
T doSomething();
<Y extends Bar> Y doAnotherThing(Foo<Y> foo);
}
更清楚地说明为什么public BarImpl doAnotherThing(Foo<BarImpl> foo)
不是覆盖此方法的正确方法。
答案 3 :(得分:1)
我相信我的原始答案是不正确的。以下似乎工作正常。只需将doSomething方法公开,它就可以在Java6下编译。
abstract class Bar {
// some neat stuff
}
class BarImpl extends Bar {
// some cool stuff
}
interface Foo<T extends Bar> {
public T doSomething();
}
class FooImpl implements Foo<BarImpl> {
public BarImpl doSomething() {
return null;
}
}
public class Test {
<T extends Bar> T doAnotherThing(Foo<T> foo) {
return foo.doSomething();
}
}