如何强制两个实例变量具有相同的泛型类型?

时间:2018-06-15 12:03:48

标签: java generics

假设我有一个包含泛型类型的两个实例变量的类,我该如何强制这些类型相同?

我还没有在其他地方发现任何类似的问题(更不用说答案了),这可能是因为我使用了错误的条款。那里有this question,但我不确定如何将它应用到我的情况中。

简而言之,如何让最后一行代码无法编译?

class Foo<T> {
    private T value;
}

class Bar {
    private Foo var1;
    private Foo var2;

    public Bar(Foo var1, Foo var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    public static void main(String[] args) {
        Foo<String> var1 = new Foo<>();
        Foo<Integer> var2 = new Foo<>();
        Bar b = new Bar(var1, var2); // this should not work
    }
}

2 个答案:

答案 0 :(得分:34)

Bar也通用:

class Bar<T> {
    private Foo<T> var1;
    private Foo<T> var2;

    public Bar(Foo<T> var1, Foo<T> var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    public static void main(String[] args) {
        Foo<String> var1 = new Foo<>();
        Foo<Integer> var2 = new Foo<>();
        Bar<String> b = new Bar<>(var1, var2); // this does not work
    }
}

通过为T使用类级别泛型参数Bar,您可以为两个实例变量强制执行相同的类型。

这也消除了@daniu在评论中提到的使用原始类型(which should never be used)的警告。

现在,如果你碰巧不使用原始类型但是想要允许不同的类型,你可以使用通配符:

使用上限,只允许键入读取(var1var2将始终生成类型为T的实现):

class Bar<T> {
    private Foo<? extends T> var1;
    private Foo<? extends T> var2;

    public Bar(Foo<? extends T> var1, Foo<? extends T> var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    public static void main(String[] args) {
        Foo<String> var1 = new Foo<>();
        Foo<Integer> var2 = new Foo<>();
        Bar<Object> b = new Bar<>(var1, var2); // this does now work
    }
}

有限下限,只允许打字(var1var2将始终使用T类型的任何实现):

class Bar<T> {
    private Foo<? super T> var1;
    private Foo<? super T> var2;

    public Bar(Foo<? super T> var1, Foo<? super T> var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    public static void main(String[] args) {
        Foo<Integer> var1 = new Foo<>();
        Foo<Number> var2 = new Foo<>();
        Bar<Integer> b = new Bar<>(var1, var2); // this does now work
    }
}

有关该主题的更多信息,请参阅:What is PECS (Producer Extends Consumer Super)?

答案 1 :(得分:2)

Lino的答案很好。我想补充一个事实:

如果您不必跟踪var的类型,但只验证它们属于同一类型,那么您可以从{{1}移动类型参数} class到它的构造函数:

Bar

这种技术适用于各种方法。