Поскольку многие ответы здесь хорошо объясняют ::
поведение, дополнительно я хотел бы уточнить, что ::
оператору не нужно иметь точно такую же сигнатуру, что и у ссылающегося функционального интерфейса, если он используется для переменных экземпляра . Предположим, нам нужен 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;
Он также не будет компилироваться, компилятор все равно будет искать статическую ссылку. Но приведенный ниже код прекрасно скомпилируется, поскольку он проходит тест is-a:
public class TestObject {
public SubTestObject testInstance(Object t){
return (SubTestObject) t;
}
}
BinaryOperator<TestObject> binary = TestObject::testInstance;
* Я только учусь, поэтому я понял, попробуй и посмотри, не стесняйся поправлять меня, если я ошибаюсь