0
votes

This may be a dumb question so please excuse my ignorance.

Lets say I have a class:

public class Foo<T extends Base> implements Bar<T> {
    private Bar<T> wrapped;
    public void setWrapped(Bar<T> input) {
        wrapped = input;
    }
}

If I call it with:

//Lets just assume methods getNewVal and getFoo exist
Bar<? extends Base> val = getNewVal();
Foo<? extends Base> foo = getFoo();
foo.setWrapped(val);

The compiler says foo.execute(val) is an error. With a message along the lines of The method setWrapped(Bar<capture#20-of ? extends Base>) in the type Foo<capture#20-of ? extends Base> is not applicable for the arguments (Bar<capture#22-of ? extends Base>).

If I try to change Foo to be

public class Foo<T extends Base> implements Bar<T> {
    private Bar<T> wrapped;
    public void setWrapped(Bar<? extends Base> input) {
        wrapped = input;
    }
}

The call to foo.setWrapped(val) no longer errors. Instead wrapped = input is an error with a message along the lines of Type mismatch: cannot convert from Bar<capture#1-of ? extends Base> to Bar<T>.

What am I doing wrong? Is there not a way to get the compiler to be okay with a call like this without casting?

1
That is because ? is not the same as ?. The compiler cannot verify that the ? in Bar<? extends Base> is the same ? as in Foo<? extends Base>, so they are not compatible. - Andreas
There's almost no way to use a wildcard as a return type, which is what you're doing in the second code example. C.f. PECS stackoverflow.com/questions/2723397/… Those wildcards are for making generics easier to use with method parameters, not return types. - markspace
Example: getNewVal() returns Bar<HomeBase>, and getFoo() returns Foo<ThirdBase>. That is perfectly valid for first two statements, but not for setWrapped(). - Andreas
Could we get some more concrete code? - Makoto
Thanks Andreas. I understand why it doesn't work that way now. Cheers! - Mike V.

1 Answers

0
votes

It looks like what you want is

public class Foo {
    private Bar<? extends Base> wrapped;
    public void setWrapped(Bar<? extends Base> input) {
        wrapped = input;
    }
}

It's not clear what the Bar interface Foo needs to implement is, though, and why Foo should have a Bar as well as be a Bar.