Dado que muchas respuestas aquí explicaron bien el ::
comportamiento, adicionalmente me gustaría aclarar que el ::
operador no necesita tener exactamente la misma firma que la interfaz funcional de referencia si se usa para variables de instancia . Supongamos que necesitamos un BinaryOperator que tenga el tipo de TestObject . De manera tradicional se implementa así:
BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {
@Override
public TestObject apply(TestObject t, TestObject u) {
return t;
}
};
Como puede ver en la implementación anónima, requiere dos argumentos TestObject y también devuelve un objeto TestObject. Para satisfacer esta condición utilizando el ::
operador, podemos comenzar con un método estático:
public class TestObject {
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
y luego llame a:
BinaryOperator<TestObject> binary = TestObject::testStatic;
Ok, se compiló bien. ¿Qué pasa si necesitamos un método de instancia? Permite actualizar TestObject con el método de instancia:
public class TestObject {
public final TestObject testInstance(TestObject t, TestObject t2){
return t;
}
public static final TestObject testStatic(TestObject t, TestObject t2){
return t;
}
}
Ahora podemos acceder a la instancia de la siguiente manera:
TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;
Este código se compila bien, pero debajo de uno no:
BinaryOperator<TestObject> binary = TestObject::testInstance;
Mi eclipse me dice "No se puede hacer una referencia estática al método no estático testInstance (TestObject, TestObject) del tipo TestObject ..."
Es justo que sea un método de instancia, pero si lo sobrecargamos de la testInstance
siguiente manera:
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;
}
}
Y llama:
BinaryOperator<TestObject> binary = TestObject::testInstance;
El código simplemente se compilará bien. Porque llamará testInstance
con un solo parámetro en lugar de uno doble. Ok, entonces, ¿qué pasó con nuestros dos parámetros? Permite imprimir y ver:
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;
}
}
Lo que dará salida:
1418481495
303563356
Test instance called. this.hashCode:1418481495
Given parameter hashCode:303563356
Ok, entonces JVM es lo suficientemente inteligente como para llamar a param1.testInstance (param2). ¿Podemos usar testInstance
desde otro recurso pero no TestObject, es decir:
public class TestUtil {
public final TestObject testInstance(TestObject t){
return t;
}
}
Y llama:
BinaryOperator<TestObject> binary = TestUtil::testInstance;
Simplemente no se compilará y el compilador dirá: "El tipo TestUtil no define testInstance (TestObject, TestObject)" . Entonces el compilador buscará una referencia estática si no es del mismo tipo. Ok, ¿y el polimorfismo? Si eliminamos los modificadores finales y agregamos nuestro SubTestObject clase :
public class SubTestObject extends TestObject {
public final TestObject testInstance(TestObject t){
return t;
}
}
Y llama:
BinaryOperator<TestObject> binary = SubTestObject::testInstance;
No se compilará también, el compilador seguirá buscando referencias estáticas. Pero el siguiente código se compilará bien ya que está pasando una prueba:
public class TestObject {
public SubTestObject testInstance(Object t){
return (SubTestObject) t;
}
}
BinaryOperator<TestObject> binary = TestObject::testInstance;
* Solo estoy estudiando, así que me di cuenta al intentar ver, siéntase libre de corregirme si estoy equivocado