2

I want to know if there are any logical differences in declaration of these two methods:

exemple 1

public static <T extends Comparable<? super T>> T findMax(List<? extends T> list)

exemple 2

public static <T extends Comparable<? super T>> T findMax(List<T> list)

Someone told me that this part <? extends T>is equivalent with <T> and the wildcard is redundant in first exemple, and he suggested me to use the code from the second exemple. Is that right?

  • 1
    Possible duplicate of [When to use generic methods and when to use wild-card?](https://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card) – Michał Krzywański Sep 17 '19 at 18:55
  • @michalk I've already read that question, but it didn't solved my problem – jennifer lawrence Sep 17 '19 at 18:59
  • yes, extends T> can take any class (implementing Comparable interface in your case) and any subclass of it, where if any class extends T it's also of T type. i.e. if T would be `A` and `B extends A` then `B` is also of type A. Generics type T can accept any class of T type and it's subclasses. The use case of wildcards are mostly when we completely don't know the type > or want to reduce it to a specified hierarchy( super T> - T and all super types, extends T> - T and all sub types). – itwasntme Sep 17 '19 at 19:03

1 Answers1

2

They are not the same.

Show this "someone" this counterproof :)

class Scratch
{
    interface A extends Comparable<A> {}
    interface B extends A {}

    public static <T extends Comparable<? super T>> T findMax(List<? extends T> list)
    {
        return null;
    }

    public static <T extends Comparable<? super T>> T findMax2(List<T> list)
    {
        return null;
    }

    public static void main(String[] args)
    {
        List<B> listOfBs = new ArrayList<>();

        A foo = Scratch.<A>findMax(listOfBs);  // fine
        A bar = Scratch.<A>findMax2(listOfBs); // compiler error
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
  • 2
    Isn't this merely a compelling argument for not using an unnecessary type witness? Drop that, and it's fine in both cases. Yes, they are different, but is the difference meaningful, or useful? – Andy Turner Sep 17 '19 at 19:14
  • 1
    @AndyTurner He asked for "any logical differences". I aim to please. – Michael Sep 17 '19 at 19:17
  • 2
    I'm with Andy on this one. The compile error is really because of the redundant type witness. If you're prepared to let Java's type resolution mechanism do its thing, then the OP's friend is right - the two constructs are equivalent. – Dawood ibn Kareem Sep 17 '19 at 19:29
  • @DawoodibnKareem "The compile error is really because of the redundant type witness." What do you mean '*really*'? The type witness is present in both cases. Redundant or not, the cause of the compiler error is the method declaration. The two methods are called in precisely the same way. The only difference in the generic type parameter declaration. Thus, that is the cause. – Michael Sep 17 '19 at 19:58
  • I have proved that the two are not equivalent. You cannot assert that they are "practically equivalent" since you cannot demonstrate every single possible "practical" case. Everyone knows that there are deficiencies in Java's type inference. That is precisely the reason why type witnesses exist in the first place; because sometimes you have not choice but to use them. – Michael Sep 17 '19 at 20:00
  • Yes but in the first case, the type witness matches what the type resolution system evaluates the type to be, so it's redundant and causes no error. In the second case, the type witness is different from what the type resolution system evaluates the type to be, and it's different in such a way that it causes an error. – Dawood ibn Kareem Sep 17 '19 at 20:00