Java Generics – ¿Método puente?

Algo llamado el concepto de “puente” relacionado con Java Generics me hizo detenerme en un punto y pensar en ello.

Por cierto, solo sé que ocurre en el nivel de bytecode y no está disponible para que lo usemos.

Pero estoy ansioso por conocer el concepto detrás del “método de puente” utilizado por el comstackdor de Java.

¿Qué pasa exactamente detrás de las escenas y por qué se usa?

Cualquier ayuda con un ejemplo sería muy apreciada.

Es un método que permite que una clase amplíe una clase genérica o implemente una interfaz genérica (con un parámetro de tipo concreto) para seguir utilizándose como tipo sin formato.

Imagina esto:

public class MyComparator implements Comparator { public int compare(Integer a, Integer b) { // } } 

Esto no se puede usar en su forma cruda, pasando dos Object s para comparar, porque los tipos se comstackn en el método de comparación (al contrario de lo que sucedería si fuera un parámetro de tipo genérico T, donde el tipo se borrará). Entonces, en lugar de eso, detrás de escena, el comstackdor agrega un “método puente”, que se ve más o menos así (si fuera fuente Java):

 public class MyComparator implements Comparator { public int compare(Integer a, Integer b) { // } //THIS is a "bridge method" public int compare(Object a, Object b) { return compare((Integer)a, (Integer)b); } } 

El comstackdor protege el acceso al método de puente, imponiendo que las llamadas explícitas directamente al resultado en un error de tiempo de comstackción. Ahora la clase también se puede usar en su forma original:

 Object a = 5; Object b = 6; Comparator rawComp = new MyComparator(); int comp = rawComp.compare(a, b); 

¿Por qué más se necesita?

Además de agregar soporte para el uso explícito de tipos crudos (que es principalmente para la compatibilidad hacia atrás) también se requieren métodos de puente para admitir el borrado de tipos. Con borrado de tipo, un método como este:

 public  T max(List list, Comparator comp) { T biggestSoFar = list.get(0); for ( T t : list ) { if (comp.compare(t, biggestSoFar) > 0) { biggestSoFar = t; } } return biggestSoFar; } 

en realidad está comstackdo en bytecode compatible con esto:

 public Object max(List list, Comparator comp) { Object biggestSoFar = list.get(0); for ( Object t : list ) { if (comp.compare(t, biggestSoFar) > 0) { //IMPORTANT biggestSoFar = t; } } return biggestSoFar; } 

Si el método del puente no existía y MyComparator un List y un MyComparator a esta función, la llamada en la línea etiquetada IMPORTANT fallaría ya que MyComparator no tendría un método llamado compare que tome dos Object s … solo uno eso toma dos Integer .

Las preguntas frecuentes a continuación son una buena lectura.

Ver también:

  • Preguntas frecuentes sobre generics: ¿qué es un método de puente?
  • Métodos de puente de Java explicados (gracias @Bozho )

Es interesante notar que el comstackdor infiere el método de MyComparator :

 public int compare(Integer a, Integer b) {/* code */} 

está tratando de anular Comparator ‘s

 public int compare(T a, T b); 

del tipo declarado Comparator . De lo contrario, el MyComparator la compare MyComparator como un método adicional (sobrecarga) y no omiso. Y como tal, no tendría un método puente creado para ello.

Si quiere entender por qué necesita un método de puente, es mejor que comprenda lo que sucede sin él. Supongamos que no hay un método de puente.

 class A{ private T value; public void set(T newVal){ value=newVal } } class B extends A{ public void set(String newVal){ System.out.println(newVal); super.set(newVal); } } 

Observe que después del borrado, el método set en A se convirtió en un public void set(Object newVal) ya que no hay límite en el parámetro Tipo T. No hay ningún método en la clase B cuya firma sea la misma que la set en A. Entonces no hay anular. Por lo tanto, cuando sucedió algo como esto:

 A a=new B(); a.set("Hello World!"); 

El polymorphism no funcionará aquí. Recuerde que debe anular el método de la clase principal en la clase hija para que pueda usar la clase padre var para desencadenar el polymorphism.

Lo que hace el método bridge es anular silenciosamente el método en la clase padre con toda la información de un método con el mismo nombre pero diferente firma. Con la ayuda del método bridge, el polymorphism funcionó. Aunque en la superficie, anulas el método de clase padre con un método de firma diferente.