Поскольку многие ответы здесь хорошо объясняется ::
поведения, кроме того, я хотел бы уточнить, что ::
оператора оленьей коже должна иметь точно такие же подпись, как ссылающийся функциональный интерфейс, если он используется для переменного экземпляра. Предположим, нам нужен 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;
* Я просто изучать, так что я понял, по попробовать и посмотреть, не стесняйтесь исправлять меня, если я ошибаюсь
Это синтаксический сахар, чтобы иметь компилятор авто- генерировать реализации интерфейса на основе функции, которую вы предоставляете (чтобы упростить использование всей лямбды с существующими кодовыми базами). – Neet
http://java.dzone.com/articles/java-lambda-expressions-vs может помочь, не смотрел в глубину темы –
@Neet это не совсем «синтаксический сахар», если только вы не можете сказать, для чего. то есть «x является синтаксическим сахаром для y». – Ingo