假设我有一个包含泛型类型的两个实例变量的类,我该如何强制这些类型相同?
我还没有在其他地方发现任何类似的问题(更不用说答案了),这可能是因为我使用了错误的条款。那里有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
}
}
答案 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)的警告。
现在,如果你碰巧不使用原始类型但是想要允许不同的类型,你可以使用通配符:
使用上限,只允许键入读取(var1
和var2
将始终生成类型为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
}
}
有限下限,只允许打字(var1
和var2
将始终使用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
这种技术适用于各种方法。