El ejemplo mostrado allí (cita de la JLS) hace que suene como los métodos de puente solo se usan en situaciones donde se usan tipos brutos.Como este no es el caso, pensé en utilizar un ejemplo en el que se usan métodos de puente para un código genérico totalmente correcto.
Considere el siguiente interfaz y la función:
public static interface Function<A,R> {
public R apply (A arg);
}
public static <A, R> R applyFunc (Function<A,R> func, A arg) {
return func.apply(arg);
}
Si utiliza el código de la siguiente manera, se utiliza un método de puente:
Function<String, String> lower = new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
};
applyFunc(lower, "Hello");
Tras el borrado, la interfaz Function
contiene el método apply(Object)Object
(que puede confirmar descompilando el bytecode). Naturalmente, si nos fijamos en el código descompilado para applyFunc
, verá que contiene una llamada al apply(Object)Object
. Object
es el límite superior de sus variables de tipo, por lo que ninguna otra firma tendría sentido.
Por lo tanto, cuando se crea una clase anónima con el método apply(String)String
, en realidad no implementa la interfaz Function
a menos que se cree un método puente. El método de puente permite que todo el código genérico ingresado haga uso de la implementación Function
.
Curiosamente, sólo si la clase implementa alguna otra interfaz con la firma apply(String)String
y sólo si el método se llama a través de una referencia de ese tipo de interfaz sería el compilador nunca emitir una llamada con esa firma.
Incluso si tengo el siguiente código:
Function<String, String> lower = ...;
lower.apply("Hello");
El compilador todavía emite una llamada a apply(Object)Object
.
En realidad, hay otra manera de conseguir el compilador para llamar apply(String)String
, pero toma ventaja del tipo mágico asignado a una expresión de creación clase anónima que no pueden de otra manera ser escrito:
new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
}.apply("Hello");
Incluso sin genéricos, los métodos de puente son necesarios para los tipos de retorno covariantes. –
El enlace BridgeMethodResolver está roto :( – BrunoJCM
@BrunoJCM good catch. He restaurado el enlace (la clase se ha movido del proyecto 'org.springframework.core' al proyecto' spring-framework': https://fisheye.springsource.org /browse/spring-framework/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java#rdc41daa3db350ef9a4b14ef1d750d79cb22cf431) – VonC