Оскільки багато відповідей тут пояснювали добре ::поведінку, додатково я хотів би уточнити, що :: оператору не потрібно мати такий самий підпис, як відповідний функціональний інтерфейс, якщо він використовується, наприклад, змінними . Припустимо, нам потрібен BinaryOperator, який має тип TestObject . Традиційно його реалізують так:
BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {
@Override
public TestObject apply(TestObject t, TestObject u) {
return t;
}
};
Як ви бачите в анонімній реалізації, він вимагає двох аргументів TestObject і також повертає об’єкт TestObject. Щоб задовольнити цю умову за допомогою ::оператора, ми можемо почати зі статичного методу:
public class TestObject {
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
а потім зателефонуйте:
BinaryOperator<TestObject> binary = TestObject::testStatic;
Добре це складено штрафу. Що робити, якщо нам потрібен метод екземпляра? Дозволяє оновити TestObject методом екземпляра:
public class TestObject {
public final TestObject testInstance(TestObject t, TestObject t2){
return t;
}
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
Тепер ми можемо отримати доступ до екземпляра, як показано нижче:
TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;
Цей код складається добре, але нижче одного:
BinaryOperator<TestObject> binary = TestObject::testInstance;
Моє затемнення підкаже мені "Неможливо зробити статичну посилання на нестатичний метод testInstance (TestObject, TestObject) від типу TestObject ..."
Досить справедливо його метод екземпляра, але якщо ми перевантажимо, testInstanceяк показано нижче:
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;
}
}
І дзвоніть:
BinaryOperator<TestObject> binary = TestObject::testInstance;
Код просто складеться добре. Тому що він буде дзвонити testInstanceз одним параметром замість подвійного. Гаразд, що сталося з нашими двома параметрами? Дозволяє роздрукувати та побачити:
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;
}
}
Що виведе:
1418481495
303563356
Test instance called. this.hashCode:1418481495
Given parameter hashCode:303563356
Гаразд, JVM досить розумний, щоб викликати param1.testInstance (param2). Чи можемо ми використовувати testInstanceз іншого ресурсу, але не TestObject, тобто:
public class TestUtil {
public final TestObject testInstance(TestObject t){
return t;
}
}
І дзвоніть:
BinaryOperator<TestObject> binary = TestUtil::testInstance;
Він просто не компілюється, і компілятор скаже: "Тип TestUtil не визначає testInstance (TestObject, TestObject)" . Тож компілятор буде шукати статичну довідку, якщо вона не одного типу. Добре, що з поліморфізмом? Якщо ми видалимо остаточні модифікатори та додамо наш клас SubTestObject :
public class SubTestObject extends TestObject {
public final TestObject testInstance(TestObject t){
return t;
}
}
І дзвоніть:
BinaryOperator<TestObject> binary = SubTestObject::testInstance;
Він також не буде компілюватися, компілятор все одно шукатиме статичну довідку. Але нижче код буде складати чудово, оскільки він проходить це тест:
public class TestObject {
public SubTestObject testInstance(Object t){
return (SubTestObject) t;
}
}
BinaryOperator<TestObject> binary = TestObject::testInstance;
* Я просто навчаюсь, тому я зрозумів, спробувавши і побачити, не соромтеся виправити мене, якщо я помиляюся