Оскільки багато відповідей тут пояснювали добре ::
поведінку, додатково я хотів би уточнити, що ::
оператору не потрібно мати такий самий підпис, як відповідний функціональний інтерфейс, якщо він використовується, наприклад, змінними . Припустимо, нам потрібен 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;
* Я просто навчаюсь, тому я зрозумів, спробувавши і побачити, не соромтеся виправити мене, якщо я помиляюся