Ponieważ wiele odpowiedzi tutaj dobrze wyjaśniało ::
zachowanie, dodatkowo chciałbym wyjaśnić, że ::
operator nie musi mieć dokładnie takiej samej sygnatury jak odsyłający interfejs funkcjonalny, jeśli jest używany do zmiennych przykładowych . Załóżmy, że potrzebujemy BinaryOperator, który ma typ TestObject . W tradycyjny sposób zaimplementowano go w następujący sposób:
BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {
@Override
public TestObject apply(TestObject t, TestObject u) {
return t;
}
};
Jak widać w anonimowej implementacji, wymaga dwóch argumentów TestObject i zwraca również obiekt TestObject. Aby spełnić ten warunek za pomocą ::
operatora, możemy zacząć od metody statycznej:
public class TestObject {
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
a następnie zadzwoń:
BinaryOperator<TestObject> binary = TestObject::testStatic;
Ok, wszystko dobrze skompilowane. A jeśli potrzebujemy metody instancji? Pozwala zaktualizować TestObject za pomocą metody instancji:
public class TestObject {
public final TestObject testInstance(TestObject t, TestObject t2){
return t;
}
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
Teraz możemy uzyskać dostęp do instancji, jak poniżej:
TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;
Ten kod kompiluje się dobrze, ale poniżej jednego nie:
BinaryOperator<TestObject> binary = TestObject::testInstance;
Moje zaćmienie mówi mi: „Nie można dokonać statycznego odwołania do metody niestatystycznej testInstance (TestObject, TestObject) z typu TestObject ...”
Słusznie jest to metoda instancji, ale jeśli przeciążymy testInstance
jak poniżej:
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;
}
}
I zadzwoń:
BinaryOperator<TestObject> binary = TestObject::testInstance;
Kod po prostu dobrze się skompiluje. Ponieważ będzie wywoływał testInstance
z pojedynczym parametrem zamiast podwójnym. Ok, więc co się stało z naszymi dwoma parametrami? Pozwala wydrukować i zobaczyć:
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;
}
}
Co da wynik:
1418481495
303563356
Test instance called. this.hashCode:1418481495
Given parameter hashCode:303563356
Ok, więc JVM jest wystarczająco inteligentny, aby wywołać param1.testInstance (param2). Czy możemy korzystać testInstance
z innego zasobu, ale nie TestObject, tj .:
public class TestUtil {
public final TestObject testInstance(TestObject t){
return t;
}
}
I zadzwoń:
BinaryOperator<TestObject> binary = TestUtil::testInstance;
Po prostu się nie skompiluje, a kompilator powie: „Typ TestUtil nie definiuje testInstance (TestObject, TestObject)” . Tak więc kompilator będzie szukał odniesienia statycznego, jeśli nie jest tego samego typu. Ok, a co z polimorfizmem? Jeśli usuniemy końcowe modyfikatory i dodamy naszą klasę SubTestObject :
public class SubTestObject extends TestObject {
public final TestObject testInstance(TestObject t){
return t;
}
}
I zadzwoń:
BinaryOperator<TestObject> binary = SubTestObject::testInstance;
Nie będzie się również kompilował, kompilator będzie nadal szukał statycznego odniesienia. Ale poniższy kod skompiluje się dobrze, ponieważ jego przekazanie jest testem:
public class TestObject {
public SubTestObject testInstance(Object t){
return (SubTestObject) t;
}
}
BinaryOperator<TestObject> binary = TestObject::testInstance;
* Właśnie studiuję, więc zrozumiałem, próbując zobaczyć, nie krępuj się mnie poprawić, jeśli się mylę