How does Collections.reverseOrder know what type parameter to use while returning Comparator

后端 未结 5 1034
野趣味
野趣味 2021-01-05 20:02

As per Java API spec, the signature of Collections.reverseOrder is

public static Comparator reverseOrder()

And the example gi

相关标签:
5条回答
  • 2021-01-05 20:36

    T is resolved based on the type of a.

    0 讨论(0)
  • 2021-01-05 20:42

    If you look at the signatures for Arrays.sort() you will see that the one you are calling has a signature of Arrays.sort(T[], Comparator<? super T>), so you are in effect supplying a type parameter in the form of the array type you pass in.

    EDIT: I made a small mistake here, and assumed that the call to reverseOrder() could infer the type, but without at least one parameter, no method could actually do that (see the link).

    If the call to Collections.reverseOrder() took a parameter, then the method could infer the type from the call. There is an overloaded version of the method that takes a Comparator<T> as an argument. We can demonstrate the inference in Eclipse with the following; hover over Collections.reverseOrder():

    
    public class CollectionsFun {
       public static void main(String[] args) {
          String[] strs = new String[] {"foo", "bar", "baz"};
          Comparator<String> comp = new Comparator<String>() {
             @Override
             public int compare(String o1, String o2) {
                return o1.compareTo(o2);
             }        
          };
          Arrays.sort(strs, Collections.reverseOrder(comp));
          System.out.println(strs);
       }
    }
    
    

    Because the call to reverseOrder() in this example takes a typed parameter, the static method can infer the type that needs to be returned. However, when you call the overloaded form of the method that takes no parameter, no type can be inferred, so you get a Comparator<Object> back instead of a Comparator<String>. You can see this by hovering over the reverseOrder() call in the code below:

    
    public class CollectionsFun {
       public static void main(String[] args) {
          String[] strs = new String[] {"foo", "bar", "baz"};
          Arrays.sort(strs, Collections.reverseOrder());
          System.out.println(strs);
       }
    } 
    
    

    As the signature to Arrays.sort() says it takes a Comparator<? super T> it matches Comparator<Object>. So this all compiles without giving you a "raw types" warning anywhere.

    Finally, if you want to show how this would work without type inference, you would do the following:

    
    public class CollectionsFun {
       public static void main(String[] args) {
          String[] strs = new String[] {"foo", "bar", "baz"};
          Arrays.sort(strs, Collections.<String>reverseOrder());
          System.out.println(strs);
       }
    }
    
    

    The type parameter supplied above ensures that the type of the Comparator that gets returned is Comparator<String>.

    0 讨论(0)
  • 2021-01-05 20:49

    Types in methods calls can be inferred.

    Xyz[] a;
    Arrays.sort(a, Collections.reverseOrder());
    

    is equivalent to

    Xyz[] a;
    Arrays.<Xyz>sort(a, Collections.<Xyz>reverseOrder());
    

    From Java SE 7 something similar works for constructors, only you need to use the "diamond 'operator'" (for not very good reasons).

    List<Xyz> xyzs = new ArrayList<>();
    
    0 讨论(0)
  • 2021-01-05 20:52

    T is being resolved to Object. This passes, since Arrays.sort(T[], Comparator<? super T>) would accept a Comparator<Object>, since Object is a supertype of T.

    Eclipse confirms that Collections.reverseOrder() is resolved to a Comparator<Object> in the code

    String[] array = new String[10];
    Arrays.sort(array, Collections.reverseOrder());
    
    0 讨论(0)
  • 2021-01-05 20:53

    Arrays.sort() knows what kind of Comparator it needs, since T is specified by the first argument (a):

    public static <T> void sort(T[] a, Comparator<? super T> c)
    

    EDIT:

    @Louis Wasserman correctly points out that we only need a Comparator<? super T>, not a Comparator<T>. Since Object is a superclass of any T, then Comparator<Object> (the default if no generic parameters are given) is sufficient.

    0 讨论(0)
提交回复
热议问题