10

How does Java know which String::compareTo method reference to use when calling Collections.sort(someListOfStrings, String::compareTo);? compareTo is not static and it needs to know the value of the "left hand side" of the comparison.

stantonk
  • 1,922
  • 1
  • 18
  • 24
  • what is this `String::compareTo` – diyoda_ Sep 05 '15 at 23:10
  • Your question is not clear: `Collections.sort` sorts the items of a collection, `String::compareTo` is used to compare two strings in that collection. if string a < string b then by doing `a.compareTo(b)` you'll get a negative result and `b.compareTo(a)` will return a positive result, either way - this result will be used to sort the items properly. – Nir Alfasi Sep 05 '15 at 23:11
  • More detail here - https://stackoverflow.com/q/35914775/3333878 – abitcode Mar 19 '20 at 11:49

2 Answers2

15

Suppose that you use method reference for Comparator interface:

Comparator<String> cmp = String::compareTo;

When you call the cmp.compare(left, right) (which is "single abstract method" or "SAM" of Comparator interface), the magic occurs:

int result = cmp.compare(left, right);
                           |     |
  /------------------------/     |
  |              /---------------/
  |              |
left.compareTo(right);

Basically all the parameters of SAM are converted to the parameters of the referred method, but this object (which is on the left side) is also counted as parameter.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • 8
    This is called an *unbound instance* method reference. – Brian Goetz Sep 06 '15 at 04:18
  • @Tagir Valeev but how does `String::compareTo`'s type match `Comparator`? The type signature doesn't match... `String`'s `compareTo` method is `public int compareTo(String anotherString)`, `Comparator` is ` int compare(String o1, String o2);` I know I'm missing something I cant quite connect the dots. – stantonk Sep 06 '15 at 21:06
  • 2
    @stantonk, think about `this` as about one more parameter, so `public int compareTo(String anotherString)` is like `public static int compareTo(String this, String anotherString)`. Generally in OOP-languages internally it works like this: the object pointer (reference) is converted to the first parameter of the function/method. – Tagir Valeev Sep 07 '15 at 01:05
  • @TagirValeev A HAH! Yes yes, it makes sense now. Python makes this explicit in instance method signatures by always requiring `self` as the first parameter. It would have to be an implied parameter, since methods have to be bound somehow to the appropriate instance for them to be methods on a class instance and know to which `this` one was referring. Thanks! – stantonk Sep 07 '15 at 04:20
  • @stantonk: note that Java 8 allows you to declare the `this` instance explicitly, if you prefer that, like `ReturnType instancemethod(MyType this, OtherParameterType arg1, …)` – Holger Sep 25 '15 at 15:26
0

OK, the source of Collections.sort() looks as follows:

public static <T> void sort(List<T> list, Comparator<? super T> c) {
   Object[] a = list.toArray();
   Arrays.sort(a, (Comparator)c);
   ListIterator i = list.listIterator();
   for (int j=0; j<a.length; j++) {
      i.next();
      i.set(a[j]);
   }
}

I think it is quite clear now. The contents is a list. It means it has an order and the items are treated one by one in that order.

TomS
  • 1,159
  • 2
  • 17
  • 35
  • sorry, that does not answer my question. What I'm trying to understand is how Java knows to use the correct `String::compareTo` method reference for each element in the list to be sorted. – stantonk Sep 06 '15 at 01:28
  • so, for instance, let's say you had a list `["c", "b", "a"]`. the first element in that list, "c", is an instance of the `String` class, which has a property of `value` that is a character array containing a single character, 'c'. `compareTo` makes a comparison between "c" and "b" deep inside the `Collections.sort` method, i.e. `if (c.compare(a[runHi++], a[lo]) < 0) `. I am not seeing how the method reference gets you from `Comparable` to `Comparator`. – stantonk Sep 06 '15 at 01:35