我在这个接口和方法中使用Java泛型做错了什么?

时间:2011-01-04 21:36:13

标签: java generics inheritance types

编辑:在这里还有另一个皱纹,我错过了,结果发挥了重大作用。 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>,所以我看不出这是怎么回事?也许我误会了什么?感谢

4 个答案:

答案 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();
}

}