¿Por qué es legal para pasar una referencia de un parámetro de método como un argumento de tipo esperado BiConsumer
cuyo método abstracto requiere dos argumentos?
Ejemplo:
class Experiment {
private String name;
public Experiment(String name) {
this.name = name;
}
public void oneParamMethod(Object o) {
System.out.println(this.name + " and " + o);
}
public <T, S> void executeBiConsumer(BiConsumer<T, S> biCon, T in1, S in2) {
biCon.accept(in1, in2);
}
public static void main(String[] args) {
// notice that the name is "INSTANCE", but it won't be printed out
Experiment exp = new Experiment("INSTANCE");
// executeBiConsumer expects a functional of two params but is given a method
// reference of one param. HOW IS THIS LEGAL?
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
}
}
Salida:
PARAM and 999
Vamos a cambiar la invocación de tal manera que el segundo argumento es no una instancia de Experiment
la siguiente manera:
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
Ahora bien, no se compilará.
- ¿Por qué la compilación de código sin quejarse si el segundo argumento es un
Experiment
ejemplo, y por qué no compila lo contrario? - ¿Por qué es válida para pasar una referencia del método de un solo parámetro como argumento que espere
BiConsumer
?
Un método de referencia hace referencia a un argumento un método de instancia que tiene en realidad tiene dos argumentos - el primer argumento es implícita - la instancia en que se ejecuta el método.
Experiment::oneParamMethod
es equivalente a (Experiment e, Object o) -> e.oneParamMethod(o)
.
El BiConsumer<T, S>
está de paso a executeBiConsumer
es una BiConsumer<Experiment,Object>
, lo que significa que debe recibir una instancia de Experiment
que el primer argumento del accept
método.
Por lo tanto
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
es válida, pero
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
no es.
Aquí hay una referencia relevante JLS ( 15.13.1 ):
En segundo lugar, dado un tipo de función objetivo con n parámetros, un conjunto de métodos potencialmente aplicables se identifica:
Si la expresión de referencia método tiene la forma ReferenceType :: [TypeArguments] Identificador, los métodos potencialmente aplicables son los métodos miembro del tipo de buscar que tiene un nombre apropiado (dada por Identifier), la accesibilidad, aridad (n o n-1) y el tipo de argumento aridad (derivado de [TypeArguments]), como se especifica en §15.12.2.1.
Dos arities diferentes, n y n-1, se consideran, para tener en cuenta la posibilidad de que esta forma se refiere tanto a un método estático o un método de instancia.
Su tipo de función específica - BiConsumer
- tiene 2 parámetros. Por lo tanto los métodos potencialmente aplicables son los métodos miembro del tipo de búsqueda ( Experiment
) que tienen el nombre apropiado ( oneParamMethod
) y aridad 2 o 1 (es decir, 1 o 2 argumentos). Esto incluye su public void oneParamMethod(Object o)
método.