0

is it possible in Java to narrow down the generic type in a subclass of a generic class? My case looks like this:

class C<T> {
  protected T foo() {...}
  protected void bar(Supplier<T> foobar) {...}
}

class A<T extends B> extends C<T> {
  public void someMethod(){
    B b = foo(); // Compiler does not complain
    bar(() -> createB()); // Compiler complains with "Type mismatch: cannot convert from B to T"
  }
}

Maybe what I did is totally stupid, but I don't get why the compiler does not complain about foo(), but about bar().

Any advice on how to do this, or why not to do this at all, is highly appreciated :)

Kind regards, Thomas

Thomas
  • 56
  • 5
  • 1
    where is `createB` and `B`? – Eugene Aug 06 '21 at 17:56
  • 3
    `T` is a `B` but `B` does not have to be a `T`. `class D extends B {}` breaks in the second case but obviously you can assign a `D` to a `B`. – luk2302 Aug 06 '21 at 17:57
  • OMG you are so right. In order to fix this "createB()" also hast to be generic with type T! Thank you so much! – Thomas Aug 06 '21 at 20:17

2 Answers2

1

It's a variance issue. You have A<T extends B> a subtype of C<T>. We also have

class C<T> {
  protected T foo() {...}
  protected void bar(Supplier<T> foobar) {...}
}

Now, when you do

B b = foo();

foo() returns T. And we know (from the class declaration) that T extends B is true. It's always safe to upcast to a supertype, so every T is a B. Now consider

bar(() -> createB());

createB is, I presume, a function which returns a B. bar is expecting a Supplier<T>. That is, bar is expecting something which produces a T. Does createB produce a T? Well, it produces a B. Can we upcast a B to a T? No, we know T extends B, but to upcast B to T we would need to know the opposite: that B extends T.

The T in bar appears in argument position (contravariant), while the T in foo appears in return position (covariant). This accounts for the difference in the ability to cast. Had we written

class A<T super B> extends C<T> {
  ...
}

Then you'd be able to do the bar example but not the foo example, because we have the opposite relation.

See What is PECS, which is related to this question. It's more about call-site variance, but the discussion of variance is still relevant nonetheless.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0

According to @luk2302 comment: createB hast to be generic itself so that you can parameterize IT to return a T extends b

Thomas
  • 56
  • 5