¿Cómo se usan las clases anónimas (internas) en Java?

¿Cuál es el uso de clases anónimas en Java? ¿Podemos decir que el uso de clases anónimas es una de las ventajas de Java?

Por una “clase anónima”, entiendo que te refieres a la clase interna anónima .

Una clase interna anónima puede resultar útil cuando se crea una instancia de un objeto con ciertos “extras”, como los métodos de sobrecarga, sin tener que crear subclase en una clase.

Tiendo a usarlo como atajo para adjuntar un oyente de evento:

button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // do something } }); 

Usar este método hace que la encoding sea un poco más rápida, ya que no necesito crear una clase extra que implemente ActionListener . Puedo crear una instancia de una clase interna anónima sin hacer una clase diferente.

Solo uso esta técnica para tareas “rápidas y sucias” donde hacer que una clase entera parezca innecesaria. Tener varias clases internas anónimas que hagan exactamente lo mismo se debe refactorizar a una clase real, ya sea una clase interna o una clase separada.

Las clases internas anónimas son efectivamente cierres, por lo que se pueden usar para emular expresiones lambda o “delegates”. Por ejemplo, toma esta interfaz:

 public interface F { B f(A a); } 

Puede usar esto anónimamente para crear una función de primera clase en Java. Supongamos que tiene el siguiente método que devuelve el primer número más grande que yo en la lista dada, o i si ningún número es mayor:

 public static int larger(final List ns, final int i) { for (Integer n : ns) if (n > i) return n; return i; } 

Y luego tiene otro método que devuelve el primer número más pequeño que yo en la lista dada, o si no hay un número más pequeño:

 public static int smaller(final List ns, final int i) { for (Integer n : ns) if (n < i) return n; return i; } 

Estos métodos son casi idénticos. Usando la función de primera clase tipo F, podemos reescribir estos en un método de la siguiente manera:

 public static  T firstMatch(final List ts, final F f, T z) { for (T t : ts) if (ff(t)) return t; return z; } 

Puede usar una clase anónima para usar el método firstMatch:

 F greaterThanTen = new F { Boolean f(final Integer n) { return n > 10; } }; int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x); 

Este es un ejemplo realmente artificial, pero es fácil ver que poder pasar funciones como si fueran valores es una característica bastante útil. Consulte "Puede su lenguaje de progtwigción hacer esto" por el propio Joel.

Una buena biblioteca para progtwigr Java en este estilo: Java funcional.

Los uso a veces como un truco de syntax para la instanciación de mapas:

 Map map = new HashMap() {{ put("key", "value"); }}; 

vs

 Map map = new HashMap(); map.put("key", "value"); 

Ahorra un poco de redundancia cuando se hacen muchas declaraciones. Sin embargo, también he tenido problemas para hacer esto cuando la clase externa necesita ser serializada a través de la comunicación remota.

La clase interna anónima se usa en el siguiente escenario:

1.) Para Overriding (Subclasificación), cuando la definición de la clase no se puede usar excepto el caso actual:

 class A{ public void methodA() { System.out.println("methodA"); } } class B{ A a = new A() { public void methodA() { System.out.println("anonymous methodA"); } }; } 

2.) Para implementar una interfaz, cuando se requiere la implementación de la interfaz solo para el caso actual:

 interface interfaceA{ public void methodA(); } class B{ interfaceA a = new interfaceA() { public void methodA() { System.out.println("anonymous methodA implementer"); } }; } 

3.) Argumento definido clase interna anónima:

  interface Foo { void methodFoo(); } class B{ void do(Foo f) { } } class A{ void methodA() { B b = new B(); b.do(new Foo() { public void methodFoo() { System.out.println("methodFoo"); } }); } } 

Se usan comúnmente como una forma verbosa de callback.

Supongo que podría decir que son una ventaja en comparación con no tenerlos, y tener que crear una clase con nombre todo el tiempo, pero los conceptos similares se implementan mucho mejor en otros idiomas (como cierres o bloques)

Aquí hay un ejemplo de swing

 myButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { // do stuff here... } }); 

Aunque todavía es bastante detallado, es mucho mejor que forzarte a definir una clase con nombre para cada oyente desechado como este (aunque dependiendo de la situación y la reutilización, ese puede ser el mejor enfoque)

Lo usa en situaciones en las que necesita crear una clase para un propósito específico dentro de otra función, por ejemplo, como oyente, como ejecutable (para engendrar un hilo), etc.

La idea es que los llames desde el interior del código de una función para que nunca los consultes en otro lugar, por lo que no necesitas nombrarlos. El comstackdor simplemente los enumera.

En esencia, son azúcar sintáctico y, en general, deben trasladarse a otro lugar a medida que crecen.

No estoy seguro si es una de las ventajas de Java, aunque si las usa (y todos las usamos con frecuencia, desafortunadamente), entonces podría argumentar que son una.

GuideLines para clase anónima.

  1. La clase anónima se declara e inicializa simultáneamente.

  2. La clase anónima debe extender o implementar a una y solo una clase o interfaz resp.

  3. Como la clase anonymouse no tiene nombre, solo se puede usar una vez.

p.ej:

 button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub } }); 
 new Thread() { public void run() { try { Thread.sleep(300); } catch (InterruptedException e) { System.out.println("Exception message: " + e.getMessage()); System.out.println("Exception cause: " + e.getCause()); } } }.start(); 

Este es también uno de los ejemplos para el tipo interno anónimo que usa hilo

Sí, las clases internas anónimas son definitivamente una de las ventajas de Java.

Con una clase interna anónima, usted tiene acceso a las variables finales y miembros de la clase circundante, y eso es útil para los oyentes, etc.

Pero una gran ventaja es que el código de clase interno, que (al menos debe estar) estrechamente acoplado a la clase / método / bloque circundante, tiene un contexto específico (la clase, el método y el bloque circundantes).

uso objetos anónimos para llamar a nuevos hilos …

 new Thread(new Runnable() { public void run() { // you code } }).start(); 

La clase interna anónima puede ser beneficiosa a la vez que proporciona diferentes implementaciones para diferentes objetos. Pero debe usarse con moderación ya que crea problemas para la legibilidad del progtwig.

Una clase interna se asocia con una instancia de la clase externa y hay dos tipos especiales: clase local y clase anónima . Una clase anónima nos permite declarar y crear instancias de una clase al mismo tiempo, por lo tanto, hace que el código sea conciso. Los usamos cuando necesitamos una clase local solo una vez, ya que no tienen un nombre.

Considere el ejemplo de doc donde tenemos una clase Person :

 public class Person { public enum Sex { MALE, FEMALE } String name; LocalDate birthday; Sex gender; String emailAddress; public int getAge() { // ... } public void printPerson() { // ... } } 

y tenemos un método para imprimir miembros que coinciden con los criterios de búsqueda como:

 public static void printPersons( List roster, CheckPerson tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); } } } 

donde CheckPerson es una interfaz como:

 interface CheckPerson { boolean test(Person p); } 

Ahora podemos hacer uso de una clase anónima que implementa esta interfaz para especificar criterios de búsqueda como:

 printPersons( roster, new CheckPerson() { public boolean test(Person p) { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; } } ); 

Aquí la interfaz es muy simple y la syntax de la clase anónima parece difícil de manejar y poco clara.

Java 8 ha introducido un término Interfaz funcional que es una interfaz con solo un método abstracto, por lo tanto podemos decir que CheckPerson es una interfaz funcional. Podemos hacer uso de Lambda Expression que nos permite pasar la función como argumento de método como:

 printPersons( roster, (Person p) -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 ); 

Podemos utilizar una interfaz funcional estándar Predicate en lugar de la interfaz CheckPerson , que reducirá aún más la cantidad de código requerido.

Uno de los principales usos de las clases anónimas en la finalización de clases, que llamó tutor finalizador . En el mundo de Java, se deben evitar los métodos de finalización hasta que realmente los necesites. Debe recordar que cuando invalide el método de finalización para las subclases, siempre debe invocar a super.finalize() también, ya que el método de finalización de super.finalize() no se invocará automáticamente y puede tener problemas con las pérdidas de memoria.

así que teniendo en cuenta el hecho mencionado anteriormente, puedes usar las clases anónimas como:

 public class HeavyClass{ private final Object finalizerGuardian = new Object() { @Override protected void finalize() throws Throwable{ //Finalize outer HeavyClass object } }; } 

Usando esta técnica, usted y sus otros desarrolladores pueden super.finalize() llamar a super.finalize() en cada subclase del HeavyClass que necesita el método de finalización.

Puedes usar la clase anónima de esta manera

 TreeSet treeSetObj = new TreeSet(new Comparator() { public int compare(String i1,String i2) { return i2.compareTo(i1); } }); 

Parece que no se menciona a nadie aquí, pero también se puede usar la clase anónima para mantener el argumento de tipo genérico (que normalmente se pierde debido a la eliminación del tipo) :

 public abstract class TypeHolder { private final Type type; public TypeReference() { // you may do do additional sanity checks here final Type superClass = getClass().getGenericSuperclass(); this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; } public final Type getType() { return this.type; } } 

Si creará una instancia de esta clase de forma anónima

 TypeHolder, Map> holder = new TypeHolder, Map>() {}; 

entonces tal instancia de holder contendrá la definición no borrada del tipo pasado.

Uso

Esto es muy útil para construir validadores / deserializadores. También puede crear instancias de tipo genérico con reflection (de modo que si alguna vez desea hacer un new T() en tipo parametrizado, ¡es bienvenido!) .

Inconvenientes / Limitaciones

  1. Debe pasar el parámetro genérico de forma explícita. Si no lo hace, se perderá el parámetro de tipo
  2. Cada instanciación le costará una clase adicional que será generada por el comstackdor que conduce a la contaminación de la ruta de clase / hinchazón del vaso

La mejor forma de optimizar el código. también, podemos usarlo para un método de anulación de una clase o interfaz.

 import java.util.Scanner; abstract class AnonymousInner { abstract void sum(); } class AnonymousInnerMain { public static void main(String []k){ Scanner sn = new Scanner(System.in); System.out.println("Enter two vlaues"); int a= Integer.parseInt(sn.nextLine()); int b= Integer.parseInt(sn.nextLine()); AnonymousInner ac = new AnonymousInner(){ void sum(){ int c= a+b; System.out.println("Sum of two number is: "+c); } }; ac.sum(); } } 

Una clase interna anónima se utiliza para crear un objeto que nunca se volverá a referenciar. No tiene nombre y se declara y crea en la misma statement. Esto se usa donde normalmente usarías la variable de un objeto. Usted reemplaza la variable con la new palabra clave, una llamada a un constructor y la definición de clase dentro de { y } .

Al escribir un progtwig de subprocesos en Java, por lo general se vería así

 ThreadClass task = new ThreadClass(); Thread runner = new Thread(task); runner.start(); 

El ThreadClass utilizado aquí sería definido por el usuario. Esta clase implementará la interfaz Runnable que se requiere para crear subprocesos. En ThreadClass , también se debe implementar el método run() (único método en Runnable ). Está claro que deshacerse de ThreadClass sería más eficiente y eso es exactamente por qué existen las clases internas anónimas.

Mira el siguiente código

 Thread runner = new Thread(new Runnable() { public void run() { //Thread does it's work here } }); runner.start(); 

Este código reemplaza la referencia hecha a la task en el ejemplo más superior. En lugar de tener una clase separada, la clase interna anónima dentro del constructor Thread() devuelve un objeto sin nombre que implementa la interfaz Runnable y anula el método run() . El método run() incluiría enunciados dentro que hacen el trabajo requerido por el hilo.

Respondiendo a la pregunta sobre si Anonymous Inner Classes es una de las ventajas de Java, tendría que decir que no estoy muy seguro ya que no estoy familiarizado con muchos lenguajes de progtwigción en este momento. Pero lo que puedo decir es que definitivamente es un método de encoding más rápido y fácil.

Referencias: Sams Teach Yourself Java en 21 días Séptima edición

Una ventaja más:
Como sabe, Java no es compatible con herencia múltiple, por lo que si utiliza clase “Thread” como clase anónima, la clase todavía tiene un espacio para que se extienda cualquier otra clase.