Also sehe ich hier tonnenweise Antworten, die ehrlich gesagt überkompliziert sind, und das ist noch untertrieben.
Die Antwort ist ziemlich einfach: **:: wird als Methodenreferenzen bezeichnet. In Methodenreferenzen findest du alle Informationen, wenn du zur Tabelle scrollst.
Lass uns jetzt einen kurzen Blick darauf werfen, was eine Methodenreferenz ist:
A::b ersetzt gewissermaßen den folgenden inline Lambda-Ausdruck: (Parameter ...) -> A.b(Parameter ...)
Um das mit deinen Fragen in Verbindung zu bringen, ist es erforderlich, ein Java-Lambda-Ausdruck zu verstehen. Was nicht schwer ist.
Ein inline Lambda-Ausdruck ähnelt einem definierten funktionalen Interface (das ist ein Interface, das genau eine Methode hat).
Lass uns kurz betrachten, was ich meine:
InterfaceX f = (x) -> x*x;
InterfaceX muss ein funktionales Interface sein. Jedes funktionale Interface, das Einzige, worauf es dem Compiler bei InterfaceX ankommt, ist, dass du das Format definierst:
InterfaceX kann eines dieser sein:
interface InterfaceX
{
public Integer callMe(Integer x);
}
Oder dieses:
interface InterfaceX
{
public Double callMe(Integer x);
}
Oder generischer:
interface InterfaceX
{
public T callMe(U x);
}
Lasst uns den ersten vorgestellten Fall und den inline Lambda-Ausdruck, den wir zuvor definiert haben, betrachten.
Vor Java 8 könntest du es ähnlich wie folgt definiert haben:
InterfaceX o = new InterfaceX(){
public int callMe(int x)
{
return x*x;
}
};
Funktional ist es dasselbe. Der Unterschied liegt eher darin, wie der Compiler dies wahrnimmt.
Nachdem wir uns den inline Lambda-Ausdruck angesehen haben, kehren wir zum Methodenreferenz (::) zurück. Nehmen wir an, du hast eine Klasse wie diese:
class Q {
public static int anyFunction(int x)
{
return x + 5;
}
}
Da die Methode anyFunction die gleichen Typen wie InterfaceX callMe hat, können wir diese beiden mit einer Methodenreferenz gleichsetzen.
Wir können es so schreiben:
InterfaceX o = Q::anyFunction;
Und das ist äquivalent zu diesem:
InterfaceX o = (x) -> Q.anyFunction(x);
Eine coole Sache und ein Vorteil von Methodenreferenzen ist, dass sie zuerst, bis du sie Variablen zuweist, typenlos sind. Du kannst sie also als Parameter an jedes ähnlich aussehende (hat die gleichen definierten Typen) funktionale Interface übergeben. Genau das passiert in deinem Fall.