Поскольку многие ответы здесь хорошо объясняют ::
поведение, дополнительно я хотел бы пояснить, что ::
оператор не должен иметь точно такую же сигнатуру, что и ссылающийся функциональный интерфейс, если он используется для переменных экземпляра. Предположим, нам нужен 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)». Таким образом, компилятор будет искать статическую ссылку, если она не того же типа. Хорошо, а как насчет полиморфизма? Если мы удалим модификаторы final и добавим наш класс 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;
* Я только учусь, поэтому я понял, попробовав, не стесняйтесь поправлять меня, если я ошибаюсь
06.03.2017