Java中的嵌套类型参数

时间:2011-11-08 23:27:06

标签: java generics type-parameter nested-generics

这是我编写的实际代码的简化示例,所以如果它有点人为,我会道歉。我想要做的是从单个嵌套类型参数中有效地获取两个类型参数。我很确定这是不可能的,但我想我会试一试。

//Not legal java code
public class Foo<C extends Collection<T>> { //where T is another type parameter
    private C coll;

    public Foo(C coll) {
        this.coll = coll;
    }

    public void add(T elem){
        this.coll.add(elem);
    }
    //UPDATED TO ADD GETTER
    /**
     * I may need to retrieve the collection again, or pass it
     * on to another function that needs the specific C type
     */
    public C getColl(){
        return coll;
    }
}
...
List<String> strings = new ArrayList<String>();
Foo<List<String>> foo = new Foo<List<String>>(strings);
foo.add("hello");

我知道我可以通过添加另一个类型参数来实现:

public class Foo<C extends Collection<T>,T>

然后我必须添加冗余:

Foo<List<String>,String> foo = new Foo<List<String>,String>(strings);

在我的真实案例中,我的泛型有时可以在implements子句中指定,如

public class Bar implements Baz<String>

必须指定第二个类型参数更加痛苦,因为它感觉它会抛出我脸上的实现细节。不得不说

Foo<Bar,String>

当String和Bar之间已经存在关系时,看起来似乎不够优雅。我得到它的Java,所以这与领域一致,但只是好奇,如果有一个解决方案。

3 个答案:

答案 0 :(得分:6)

这是不可能的,我不认为这是理想的,因为你现有的课程中没有任何东西需要不变性。

Foo<T,C extends Collection<T>>

通常可以

Foo<T,C extends Collection<? super T>>

如果有T的唯一原因是允许变异集合。

注意,如果您担心必须经常指定两个类型参数,则可以创建一个浅子类:

class DerivedFoo<T> extends Foo<Collection<T>,T>

您可以使用工厂方法来避免在创建时双重指定

public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c)

您还可以将界面抽象为interface,以获得上述DerivedFoo带来的简明类型的好处。

答案 1 :(得分:2)

为什么不使用T作为唯一的类型参数,如:

public class Foo<T> { //where T is another type parameter
private Collection<T> coll;

public Foo(Collection<T> coll) {
    this.coll = coll;
}

public void add(T elem){
    this.coll.add(elem);
}

答案 2 :(得分:2)

在Java7之前,构造函数不进行类型推断,解决方法是使用静态工厂方法。那不再是必要的了。在Java 7中,您可以

Foo<List<String>,String> foo = new Foo<>(strings);

关于TC,如果我们有2个类型参数,它们之间存在约束,则必须有一定程度的冗余。在您的示例中,由于一个参数C完全指示另一个参数T,因此冗余似乎无法忍受。我没有看到解决方案。

但如果重新排序类型参数,你可能会感觉更好

Foo<String,Bar> foo = new Foo<>(bar);

所以我们首先声明String;然后进一步提供Baz<String> Bar