I know it may have something to do with Generic and Covariant return types. But I can not make it through.
Given two classes where Apple extends Fruit.
public class TestReturnValue {
public static Supplier<? extends Fruit> conFruitExt = Apple::new;
public static Supplier<Fruit> conFruit = Apple::new; // Compiles
public static final Supplier<Fruit> supApple = supplyApple(); // Compile ERROR
private static Supplier<Apple> supplyApple() {
return Apple::new;
}
public static void main(String[] args) {
Fruit fruitExt = conFruitExt.get();
Fruit fruit = conFruit.get();
System.out.println(fruitExt);
System.out.println(fruit);
}
}
What is the different between conFruitExt and conFruit? They both are constructor of Apple, and calling get() create apple instances.
Does the additional ? extends part of conFruitExt type make any difference?
Update1 2020/11/19
As suggestted answer says, question mark in generic by jonrsharpe, Supplier<Fruit> does not compile to Suppier<Apple>, so public static final Supplier<Fruit> supApple = TestReturnValue::supplyApple; does not compile.
But as method supplyApple()'s return value indicates Apple::new is type of Supplier<Apple>, why does public static Supplier<Fruit> conFruit = Apple::new compiles. Doesn't it assign a Supplier<Apple> instance to Supplier<Fruit>?
By doing this:
you are creating a poly expression in
Apple::new. These are inferred by the compiler in the context of usage. Think about it: if I give you justApple::new- can you tell me what that is? ASupplier? Or aProvider(may be such a functional interface exists), etc? Thus these types are concluded from the surrounding context in which are used. It's like the compiler did:which is perfectly legal (this is not what happens, but to make it easier for you to understand).
In the other method you have told what the return type is, explicitly:
it is a
Supplier<Apple>. Since generics are invariant, the second assignment fails.