it-swarm.com.de

:: (Doppelpunkt) Operator in Java 8

Ich habe den Java 8-Quellcode untersucht und fand diesen speziellen Teil des Codes sehr überraschend:

//defined in IntPipeline.Java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
    return evaluate(ReduceOps.makeInt(op));
}

@Override
public final OptionalInt max() {
    return reduce(Math::max); //this is the gotcha line
}

//defined in Math.Java
public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

Ist Math::max so etwas wie ein Methodenzeiger? Wie wird eine normale static-Methode in IntBinaryOperator konvertiert?

829
Narendra Pathai

Normalerweise würde man die reduce-Methode mit Math.max(int, int) wie folgt aufrufen:

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

Dies erfordert eine Menge Syntax, um nur Math.max aufzurufen. Hier kommen Lambda-Ausdrücke ins Spiel. Seit Java 8 ist es erlaubt, dasselbe auf viel kürzere Weise zu tun:

reduce((int left, int right) -> Math.max(left, right));

Wie funktioniert das? Der Java-Compiler "erkennt", dass Sie eine Methode implementieren möchten, die zwei ints akzeptiert und eine int zurückgibt. Dies entspricht den formalen Parametern der einzigen Methode der Schnittstelle IntBinaryOperator (dem Parameter der Methode reduce, die Sie aufrufen möchten). Der Compiler erledigt also den Rest für Sie - er geht davon aus, dass Sie IntBinaryOperator implementieren möchten.

Da Math.max(int, int) selbst die formalen Anforderungen von IntBinaryOperator erfüllt, kann es direkt verwendet werden. Da Java 7 über keine Syntax verfügt, mit der eine Methode selbst als Argument übergeben werden kann (Sie können nur Methodenergebnisse übergeben, niemals Methodenverweise), wurde die ::-Syntax in Java 8 eingeführt, um auf Methoden zu verweisen:

reduce(Math::max);

Beachten Sie, dass dies vom Compiler und nicht zur Laufzeit von der JVM interpretiert wird! Obwohl für alle drei Codeausschnitte unterschiedliche Bytecodes erzeugt werden, sind sie semantisch gleich, sodass die letzten beiden als kurze (und wahrscheinlich effizientere) Versionen der obigen IntBinaryOperator-Implementierung betrachtet werden können!

(Siehe auch Übersetzung von Lambda-Ausdrücken )

915
isnot2bad

:: heißt Methodenreferenz. Es ist im Grunde ein Hinweis auf eine einzelne Methode. Das heißt es bezieht sich auf eine vorhandene Methode anhand des Namens.

Kurze Erklärung:
Nachfolgend finden Sie ein Beispiel für einen Verweis auf eine statische Methode:

class Hey {
     public static double square(double num){
        return Math.pow(num, 2);
    }
}

Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);

square kann wie Objektreferenzen weitergegeben und bei Bedarf ausgelöst werden. Tatsächlich kann es genauso einfach als Verweis auf "normale" Methoden von Objekten verwendet werden wie static. Zum Beispiel:

class Hey {
    public double square(double num) {
        return Math.pow(num, 2);
    }
}

Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);

Function ist eine funktionale Schnittstelle. Um :: vollständig zu verstehen, ist es auch wichtig, funktionale Schnittstellen zu verstehen. Eine funktionale Schnittstelle ist eine Schnittstelle mit nur einer abstrakten Methode.

Beispiele für funktionale Schnittstellen sind Runnable, Callable und ActionListener.

Function oben ist eine funktionale Schnittstelle mit nur einer Methode: apply. Es braucht ein Argument und erzeugt ein Ergebnis.


Der Grund, warum ::s großartig ist, ist dass :

Methodenreferenzen sind Ausdrücke, die dieselbe Behandlung wie Lambda-Ausdrücke (...) haben, aber anstatt einen Methodenkörper anzugeben, referenzieren sie eine vorhandene Methode mit Namen.

Z.B. anstatt den Lambda-Körper zu schreiben

Function<Double, Double> square = (Double x) -> x * x;

Sie können es einfach tun

Function<Double, Double> square = Hey::square;

Zur Laufzeit verhalten sich diese beiden square-Methoden genau gleich. Der Bytecode kann derselbe sein oder nicht (obwohl im obigen Fall derselbe Bytecode generiert wird; kompilieren Sie den obigen Code und prüfen Sie mit javap -c).

Das einzige Hauptkriterium, das erfüllt werden muss, ist: Die von Ihnen bereitgestellte Methode sollte eine ähnliche Signatur aufweisen wie die Methode der funktionalen Schnittstelle, die Sie als Objektreferenz verwenden.

Das Folgende ist illegal:

Supplier<Boolean> p = Hey::square; // illegal

square erwartet ein Argument und gibt eine double zurück. Die get-Methode in Supplier gibt einen Wert zurück, nimmt jedoch kein Argument an. Dies führt somit zu einem Fehler. 

Eine Methodenreferenz bezieht sich auf die Methode einer funktionalen Schnittstelle. (Wie bereits erwähnt, können funktionale Schnittstellen jeweils nur eine Methode haben). 

Einige weitere Beispiele: Die accept-Methode in Consumer nimmt eine Eingabe an, gibt aber nichts zurück.

Consumer<Integer> b1 = System::exit;   // void exit(int status)
Consumer<String[]> b2 = Arrays::sort;  // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)

class Hey {
    public double getRandom() {
        return Math.random();
    }
}

Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result

Oben, getRandom nimmt kein Argument und gibt eine double zurück. Daher kann jede funktionale Schnittstelle verwendet werden, die die Kriterien erfüllt: keine Argumente verwenden und double zurückgeben

Ein anderes Beispiel:

Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");

Bei parametrisierten Typen:

class Param<T> {
    T elem;
    public T get() {
        return elem;
    }

    public void set(T elem) {
        this.elem = elem;
    }

    public static <E> E returnSame(E elem) {
        return elem;
    }
}

Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;

Function<String, String> func = Param::<String>returnSame;

Methodenreferenzen können unterschiedliche Stile haben, aber im Grunde bedeuten sie alle dasselbe und können einfach als Lambdas visualisiert werden:

  1. Eine statische Methode (ClassName::methName)
  2. Eine Instanzmethode eines bestimmten Objekts (instanceRef::methName)
  3. Eine Supermethode eines bestimmten Objekts (super::methName)
  4. Eine Instanzmethode eines beliebigen Objekts eines bestimmten Typs (ClassName::methName)
  5. Eine Klassenkonstruktorreferenz (ClassName::new)
  6. Eine Array-Konstruktorreferenz (TypeName[]::new)

Weitere Informationen finden Sie unter http://cr.openjdk.Java.net/~briangoetz/lambda/lambda-state-final.html .

426
Jatin

Ja, das ist wahr. Der ::-Operator wird für die Methodenreferenzierung verwendet. Daher kann man static -Methoden aus Klassen extrahieren, indem man sie oder Methoden aus Objekten verwendet. Der gleiche Operator kann auch für Konstruktoren verwendet werden. Alle hier genannten Fälle sind im nachstehenden Codebeispiel veranschaulicht.

Die offizielle Dokumentation von Oracle finden Sie hier .

Sie können einen besseren Überblick über die Änderungen des JDK 8 im this article haben. Im Abschnitt Method/Constructor referencing wird auch ein Codebeispiel bereitgestellt:

interface ConstructorReference {
    T constructor();
}

interface  MethodReference {
   void anotherMethod(String input);
}

public class ConstructorClass {
    String value;

   public ConstructorClass() {
       value = "default";
   }

   public static void method(String input) {
      System.out.println(input);
   }

   public void nextMethod(String input) {
       // operations
   }

   public static void main(String... args) {
       // constructor reference
       ConstructorReference reference = ConstructorClass::new;
       ConstructorClass cc = reference.constructor();

       // static method reference
       MethodReference mr = cc::method;

       // object method reference
       MethodReference mr2 = cc::nextMethod;

       System.out.println(cc.value);
   }
}
50
Olimpiu POP

:: ist ein neuer Operator, der in Java 8 enthalten ist und zum Verweisen auf eine Methode einer vorhandenen Klasse verwendet wird. Sie können statische Methoden und nicht statische Methoden einer Klasse referenzieren.

Um statische Methoden zu referenzieren, lautet die Syntax:

ClassName :: methodName 

Für das Verweisen auf nicht statische Methoden lautet die Syntax

objRef :: methodName

Und

ClassName :: methodName

Die einzige Voraussetzung für das Referenzieren einer Methode ist, dass die Methode in einer funktionalen Schnittstelle vorhanden ist, die mit der Methodenreferenz kompatibel sein muss. 

Wenn die Methodenreferenzen ausgewertet werden, erstellen Sie eine Instanz der funktionalen Schnittstelle. 

Gefunden auf: http://www.speakingcs.com/2014/08/method-references-in-Java-8.html

24
sreenath

Dies ist eine Methodenreferenz in Java 8. Die Oracle-Dokumentation ist hier .

Wie in der Dokumentation angegeben ...

Die Methodenreferenz Person :: compareByAge ist eine Referenz auf eine statische Methode.

Das folgende Beispiel zeigt einen Verweis auf eine Instanzmethode einer bestimmtes Objekt:

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

Die Methodenreferenz myComparisonProvider :: compareByName ruft die Methode compareByName .__ auf. das ist Teil des Objekts myComparisonProvider. Die JRE schließt die Methodentypargumente, die in diesem Fall (Person, Person) sind.

19
david99world

Es scheint etwas spät zu sein, aber hier sind meine zwei Cents. Ein Lambda-Ausdruck wird zum Erstellen anonymer Methoden verwendet. Es wird lediglich eine vorhandene Methode aufgerufen, es ist jedoch klarer, die Methode direkt über ihren Namen zu referenzieren. Und method reference ermöglicht dies mit dem Methodenreferenzoperator ::.

Betrachten Sie die folgende einfache Klasse, in der jeder Mitarbeiter einen Namen und eine Note hat.

public class Employee {
    private String name;
    private String grade;

    public Employee(String name, String grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}

Angenommen, wir haben eine Liste von Mitarbeitern, die nach einer Methode zurückgegeben werden, und wir möchten die Mitarbeiter nach ihrer Besoldungsgruppe sortieren. Wir wissen, dass wir anonymous class verwenden können als:

    List<Employee> employeeList = getDummyEmployees();

    // Using anonymous class
    employeeList.sort(new Comparator<Employee>() {
           @Override
           public int compare(Employee e1, Employee e2) {
               return e1.getGrade().compareTo(e2.getGrade());
           }
    });

wo getDummyEmployee () ist eine Methode als: 

private static List<Employee> getDummyEmployees() {
        return Arrays.asList(new Employee("Carrie", "C"),
                new Employee("Farhan", "F"),
                new Employee("Brian", "B"),
                new Employee("Donald", "D"),
                new Employee("Adam", "A"),
                new Employee("Evan", "E")
                );
    }

Nun wissen wir, dass Comparator eine funktionale Schnittstelle ist. Ein Functional Interface hat genau eine abstrakte Methode (obwohl es eine oder mehrere Standard- oder statische Methoden enthalten kann). Der Lambda-Ausdruck ermöglicht die Implementierung von @FunctionalInterface, sodass eine funktionale Schnittstelle nur eine abstrakte Methode haben kann. Wir können Lambda-Ausdruck verwenden als:

employeeList.sort((e1,e2) -> e1.getGrade().compareTo(e2.getGrade())); // lambda exp

Es scheint alles gut zu sein, aber was ist, wenn die Klasse Employee auch eine ähnliche Methode bereitstellt:

public class Employee {
    private String name;
    private String grade;
    // getter and setter
    public static int compareByGrade(Employee e1, Employee e2) {
        return e1.grade.compareTo(e2.grade);
    }
}

In diesem Fall wird die Verwendung des Methodennamens selbst klarer. Daher können wir uns direkt auf die Methode beziehen, indem wir die Methodenreferenz als verwenden:

employeeList.sort(Employee::compareByGrade); // method reference

Gemäß docs gibt es vier Arten von Methodenverweisen:

+----+-------------------------------------------------------+--------------------------------------+
|    | Kind                                                  | Example                              |
+----+-------------------------------------------------------+--------------------------------------+
| 1  | Reference to a static method                          | ContainingClass::staticMethodName    |
+----+-------------------------------------------------------+--------------------------------------+
| 2  |Reference to an instance method of a particular object | containingObject::instanceMethodName | 
+----+-------------------------------------------------------+--------------------------------------+
| 3  | Reference to an instance method of an arbitrary object| ContainingType::methodName           |
|    | of a particular type                                  |                                      |  
+----+-------------------------------------------------------+--------------------------------------+
| 4  |Reference to a constructor                             | ClassName::new                       |
+------------------------------------------------------------+--------------------------------------+
18
i_am_zero

:: Operator wurde in Java 8 für Methodenverweise eingeführt. Eine Methodenreferenz ist die Abkürzungssyntax für einen Lambda-Ausdruck, der nur eine Methode ausführt. Hier ist die allgemeine Syntax einer Methodenreferenz:

Object :: methodName

Wir wissen, dass wir Lambda-Ausdrücke anstelle einer anonymen Klasse verwenden können. Aber manchmal ist der Lambda-Ausdruck wirklich nur ein Aufruf einer Methode, zum Beispiel:

Consumer<String> c = s -> System.out.println(s);

Um den Code übersichtlicher zu machen, können Sie diesen Lambda-Ausdruck in eine Methodenreferenz umwandeln:

Consumer<String> c = System.out::println;
4
Vaibhav9518

Das :: wird als Methodenreferenz bezeichnet. Nehmen wir an, wir möchten eine berechnePreis-Methode der Klasse Purchase aufrufen. Dann können wir es schreiben als:

Purchase::calculatePrice

Es kann auch als Kurzform des Schreibens des Lambda-Ausdrucks angesehen werden, weil Methodenreferenzen in Lambda-Ausdrücke konvertiert werden.

3
Sonu

Zur Laufzeit verhalten sie sich genau gleich. Der Bytecode kann/ist nicht derselbe (Für obige Incase wird derselbe Bytecode generiert (complie oben und javaap -c;) überprüfen.

Zur Laufzeit verhalten sie sich genau gleich .method (math :: max); es erzeugt die gleiche Mathematik (siehe oben und javap -c;) überprüfen.

2
Alfa khatoon

return reduce(Math::max); ist NICHT EQUAL zu return reduce(max());

Aber es bedeutet so etwas:

IntBinaryOperator myLambda = (a, b)->{(a >= b) ? a : b};//56 keystrokes I had to type -_-
return reduce(myLambda);

Sie können einfach 47 Tastenanschläge speichern speichern, wenn Sie so schreiben

return reduce(Math::max);//Only 9 keystrokes ^_^
2
Jude Niroshan

In Java-8 Streams Reducer Reducer ist in einfachen Arbeiten eine Funktion, die zwei Werte als Eingabe übernimmt und das Ergebnis nach einer Berechnung zurückgibt. Dieses Ergebnis wird bei der nächsten Iteration eingespeist.

im Falle der Math: max-Funktion gibt die Methode immer maximal zwei Werte zurück, und am Ende haben Sie die größte Zahl zur Hand.

2
Pramod

In älteren Java-Versionen können Sie anstelle von "::" oder lambd Folgendes verwenden:

public interface Action {
    void execute();
}

public class ActionImpl implements Action {

    @Override
    public void execute() {
        System.out.println("execute with ActionImpl");
    }

}

public static void main(String[] args) {
    Action action = new Action() {
        @Override
        public void execute() {
            System.out.println("execute with anonymous class");
        }
    };
    action.execute();

    //or

    Action actionImpl = new ActionImpl();
    actionImpl.execute();
}

Oder zur Methode übergehen:

public static void doSomething(Action action) {
    action.execute();
}

Die vorherigen Antworten sind in Bezug auf die Funktionsweise der ::-Methode ziemlich vollständig. Zusammenfassend bietet es eine Möglichkeit, auf eine Methode (oder einen Konstruktor) zu verweisen, ohne sie auszuführen. Wenn sie ausgewertet wird, erstellt sie eine Instanz der funktionalen Schnittstelle, die den Zieltypkontext bereitstellt.

Im Folgenden finden Sie zwei Beispiele zum Suchen eines Objekts mit dem Maximalwert in einer ArrayList WITH und WITHOUT Verwendung der ::-Methodenreferenz. Erklärungen finden Sie in den Kommentaren unten.


OHNE die Verwendung von ::

import Java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

class ByVal implements Comparator<MyClass> {
    // no need to create this class when using method reference
    public int compare(MyClass source, MyClass ref) {
        return source.getVal() - ref.getVal();
    }
}

public class FindMaxInCol {
    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, new ByVal());
    }
}

MIT der Verwendung von ::

import Java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

public class FindMaxInCol {
    static int compareMyClass(MyClass source, MyClass ref) {
        // This static method is compatible with the compare() method defined by Comparator. 
        // So there's no need to explicitly implement and create an instance of Comparator like the first example.
        return source.getVal() - ref.getVal();
    }

    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, FindMaxInCol::compareMyClass);
    }
}
1
Liutong Chen

Also Ich sehe hier Unmengen von Antworten, die ehrlich gesagt zu kompliziert sind, und das ist eine Untertreibung.

Die Antwort ist ziemlich einfach: :: es heißt eine Methode Referenzen https://docs.Oracle.com/javase/tutorial/Java /javaOO/methodreferences.html

Ich werde also nicht kopieren und einfügen. Auf dem Link finden Sie alle Informationen, wenn Sie nach unten zur Tabelle scrollen.


Werfen wir nun einen kurzen Blick auf die Methodenreferenzen:

A :: B etwas ersetzt den folgenden Inline-Lambda-Ausdruck: (Parameter ...) -> AB (Parameter ...)

Um dies mit Ihren Fragen in Beziehung zu setzen, ist es notwendig, einen Java lambda Ausdruck zu verstehen. Das ist nicht schwer.

Ein Inline-Lambda-Ausdruck ähnelt einer funktionalen Schnittstelle ( defined (dh einer Schnittstelle mit mindestens einer Methode) . Werfen wir einen kurzen Blick auf das, was ich meine:

InterfaceX f = (x) -> x*x; 

InterfaceX muss eine funktionierende Schnittstelle sein. Jede funktionale Schnittstelle. Das einzige, was an InterfaceX für diesen Compiler wichtig ist, ist, dass Sie das Format definieren:

InterfaceX kann Folgendes sein:

interface InterfaceX
{
    public Integer callMe(Integer x);
}

oder dieses

interface InterfaceX
{
    public Double callMe(Integer x);
}

oder allgemeiner:

interface InterfaceX<T,U>
{
    public T callMe(U x);
}

Nehmen wir den ersten vorgestellten Fall und den Inline-Lambda-Ausdruck, den wir zuvor definiert haben.

Vor Java 8 hätten Sie es ähnlich wie folgt definieren können:

 InterfaceX o = new InterfaceX(){
                     public int callMe (int x, int y) 
                       {
                        return x*x;
                       } };

Funktionell ist es dasselbe. Der Unterschied liegt eher darin, wie der Compiler dies wahrnimmt.

Nachdem wir uns den Inline-Lambda-Ausdruck angesehen haben, kehren wir zu den Methodenreferenzen (: :) zurück. Angenommen, Sie haben eine Klasse wie die folgende:

class Q {
        public static int anyFunction(int x)
             {
                 return x+5;
             } 
        }

Da method anyFunctions dieselben 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 gleichbedeutend mit:

InterfaceX o = (x) -> Q.anyFunction(x);

Eine coole Sache und ein Vorteil von Methodenreferenzen ist, dass sie zunächst typenlos sind, bis Sie sie Variablen zuweisen. Sie können sie also als Parameter an jede gleich aussehende Funktionsschnittstelle (mit denselben definierten Typen) übergeben. Welches ist genau das, was in Ihrem Fall passiert

1
Nertan Lucian

Da viele Antworten hier ::-Verhalten gut erklärt haben, möchte ich außerdem klarstellen, dass ::operator nicht genau dieselbe Signatur wie das referenzierende Functional Interface haben muss, wenn es für Instanzvariablen verwendet wird. Nehmen wir an, wir brauchen einen BinaryOperator , der den Typ TestObject hat. In traditioneller Weise ist es so implementiert:

BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {

        @Override
        public TestObject apply(TestObject t, TestObject u) {

            return t;
        }
    };

Wie Sie in der anonymen Implementierung sehen, sind zwei TestObject-Argumente erforderlich, und es wird auch ein TestObject-Objekt zurückgegeben. Um diese Bedingung mit dem ::-Operator zu erfüllen, können wir mit einer statischen Methode beginnen:

public class TestObject {


    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

und dann anrufen:

BinaryOperator<TestObject> binary = TestObject::testStatic;

Ok, es ist gut kompiliert. Was ist, wenn wir eine Instanzmethode benötigen? UpdateObject mit Instanzmethode aktualisieren:

public class TestObject {

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Jetzt können wir wie folgt auf die Instanz zugreifen:

TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;

Dieser Code kompiliert gut, aber unter einem nicht:

BinaryOperator<TestObject> binary = TestObject::testInstance;

Mein Eclipse sagt mir "Kann keine statische Referenz auf die nicht statische Methode testInstance (TestObject, TestObject) vom Typ TestObject herstellen ..."

Fairerweise ist es eine Instanzmethode, aber wenn wir testInstance wie folgt überladen:

public class TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Und Ruf an:

BinaryOperator<TestObject> binary = TestObject::testInstance;

Der Code wird einfach kompiliert. Weil es testInstance mit einem einzigen Parameter anstelle eines doppelten Parameters aufruft. Ok Was ist also mit unseren zwei Parametern passiert? Lass uns ausdrucken und sehen:

public class TestObject {

    public TestObject() {
        System.out.println(this.hashCode());
    }

    public final TestObject testInstance(TestObject t){
        System.out.println("Test instance called. this.hashCode:" 
    + this.hashCode());
        System.out.println("Given parameter hashCode:" + t.hashCode());
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Was wird ausgegeben:

 1418481495  
 303563356  
 Test instance called. this.hashCode:1418481495
 Given parameter hashCode:303563356

Ok, also ist JVM intelligent genug, um param1.testInstance (param2) aufzurufen. Können wir testInstance von einer anderen Ressource verwenden, aber nicht von TestObject, d. H .:

public class TestUtil {

    public final TestObject testInstance(TestObject t){
        return t;
    }
}

Und Ruf an:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

Es wird einfach nicht kompiliert und der Compiler wird Folgendes sagen: "Der Typ TestUtil definiert nicht testInstance (TestObject, TestObject)". Der Compiler sucht also nach einer statischen Referenz, wenn es sich nicht um denselben Typ handelt. Ok Was ist mit Polymorphismus? Wenn wir letzte Modifizierer entfernen und unsere SubTestObject -Klasse hinzufügen:

public class SubTestObject extends TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

}

Und Ruf an:

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

Es wird nicht so gut kompiliert, der Compiler sucht jedoch nach statischen Referenzen. Aber der folgende Code lässt sich gut kompilieren, da er is-test besteht:

public class TestObject {

    public SubTestObject testInstance(Object t){
        return (SubTestObject) t;
    }

}

BinaryOperator<TestObject> binary = TestObject::testInstance;

* Ich lerne gerade, also habe ich es durch Versuch herausgefunden und sehe, fühle mich frei, mich zu korrigieren, wenn ich falsch liege

1
HRgiger

Ich fand diese Quelle sehr interessant.

Tatsächlich wird aus Lambda ein Doppelpunkt . Der Doppelpunkt ist lesbarer .. _. Wir folgen diesen Schritten:

SCHRITT 1:

// We create a comparator of two persons
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

SCHRITT 2:

// We use the interference
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

SCHRITT 3:

// The magic
Comparator c = Comparator.comparing(Person::getAge());
1
Husam Bdr

Der Doppelpunkt, d. H. Der Operator :: wird in Java 8 als Methodenreferenz eingeführt. Die Methodenreferenz ist eine Form des Lambda-Ausdrucks, mit der auf die vorhandene Methode anhand ihres Namens verwiesen wird.

Klassenname :: Methodenname

ex:-

  • stream.forEach (Element -> System.out.println (Element))

Mit Doppelpunkt:

  • stream.forEach (System.out :: println (Element))
0