Make Bar
also generic:
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
}
}
By using a class level generic parameter T
for Bar
you can enforce the same types for both instance variables.
This eliminates also the warning of using raw types (which should never be used) as mentioned by @daniu in the comments.
Now if you happen to not use raw types but want to allow not the same types, you can work with wildcards:
With upper bounded, which only allow typed reading (var1
and var2
will always produce an implementation of type 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
}
}
And with lower bounded, which only allow typed writing (var1
and var2
will always consume any implementation of type 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
}
}
For more on that topic you can read: What is PECS (Producer Extends Consumer Super)?