How can I force two instance variables to be of the same generic type?

vvye :

Assuming I have a class with two instance variables of generic type, how can I force those types to be the same?

I haven't found any similar questions elsewhere (let alone answers), which may be because I'm using terms wrong. There's this question, but I'm not sure how to apply it to my situation.

In short, how can I get this last line of code to not compile?

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
    }
}
Lino :

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)?

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=35329&siteId=1