Instanciando un objeto Java con un método pasado

Han pasado algunos años desde que estuve muy interesado en Java. Volviendo a eso, veo este patrón por todas partes:

ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
  public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
    // do work
  }
});

Esto se parece más a la programación funcional para mí. Es un buen patrón, pero ¿cómo es posible pasar un método como este? En los viejos tiempos, una clase era una clase y, una vez compilada, poco se podía hacer.

Mis preguntas son las siguientes:

  1. Alguien me puede decir como se llama este patrón?
  2. ¿Cómo puedo escribir una clase que se pueda instanciar de esta manera?
  3. ¿Existen otros ejemplos útiles de patrones funcionales que hayan llegado a Java?
  4. ¿Qué necesito en Google para leer más sobre esto?

Gracias.

preguntado el 12 de junio de 12 a las 11:06

4 Respuestas

Esto pasa una clase anónima, no un método.

Este es un patrón típico, no solo en la programación Swing, sino en cualquier lugar donde necesite (con suerte) implementaciones cortas y "desechables" de una interfaz o clase que no necesita ser reutilizada, en lugar de crear un completo implementación.

Cualquier clase/interfaz se puede instanciar de esta manera, no tiene nada de especial:

public interface Foo {
    String foo();
}

...

public class Main {
    public static void main(String[] args) {
        System.out.println(new Foo() {
            public String foo() {
                return "plugh";
            }
        });
    }
}

Las clases internas anónimas también obtienen sus propios archivos de clase, aunque su fuente esté incrustada.

En este ejemplo, un Main$1.class se generará un archivo para la clase interna anónima, además del esperado Main.class archivo.

Respondido el 11 de enero de 13 a las 20:01

Una "clase interna anónima", para ser pedante :-) Para el OP, estos han sido parte de Java desde el principio. - Péter Török

Ah, y onRatingChanged es un método estático. Gracias por tu ayuda, me siento un poco tonto ahora :) - superluminario

@superluminary No, no es un método estático; si lo fuera, tendría un static palabra clave. Además, los métodos estáticos no se pueden anular, solo se pueden ocultar. - David Newton

Lo siento, quise decir abstracto. - superluminario

@superluminary Eso puede ser, pero no tienen ser - estar. En este caso, suponiendo que se trata de código Anroid, es una implementación del método abstracto de una interfaz. (Aunque "abstracto" en una interfaz me parece extraño). - David Newton

La declaración: new OnRatingBarChangeListener() crea una nueva instancia de una clase. La siguiente parte dentro de las llaves es la definición de la clase.

En este caso, esa clase en una clase anónima que implementa la interfaz nombrada.

Las clases anónimas son clases que se declaran sin nombre y, por lo tanto, no se pueden usar como clases regulares con nombre.

Este patrón es muy común cuando se usan oyentes, que a menudo contienen solo uno o unos pocos métodos que realizan una tarea casi trivial.

Respondido el 12 de junio de 12 a las 11:06

Este es el patrón de escucha. La barra de calificación toma una implementación de OnRatingBarChangeListener y llama a su onRatingChanged método en el evento apropiado.

Puede usar una instancia de cualquier clase que implemente OnRatingBarChangeListener. Entonces puede usar una clase con nombre propio o puede pasarle una clase anónima como en el ejemplo. La clase anónima del ejemplo es efectivamente una clase sin nombre que amplía Object e implementa OnRatingBarChangeListener. Dado que la clase no tiene nombre, no se puede hacer referencia a ella, por lo que la instancia pasada es la única instancia existente.

Respondido el 12 de junio de 12 a las 11:06

Esto se llama "patrón de observador". Un buen ejemplo de esto es agregar detectores de acción para el botón Java u otro componente. Por ejemplo,

myButton.addActionListener(
                new java.awt.event.ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    //Work here
                }
            });

Aquí "myButton" es el sujeto y ActionListener es el observador.

Respondido el 12 de junio de 12 a las 11:06

En mi opinión, al no discutir la naturaleza raíz de lo que está sucediendo, al menos se pierde un poco el punto del OP: mostrar un ejemplo esencialmente idéntico realmente no ayuda a explicar nada. - David Newton

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.