¿Para qué sirven las clases anónimas en Java? ¿Podemos decir que el uso de la clase anónima es una de las ventajas de Java?
¿Para qué sirven las clases anónimas en Java? ¿Podemos decir que el uso de la clase anónima es una de las ventajas de Java?
Respuestas:
Por "clase anónima", supongo que te refieres a la clase interna anónima .
Una clase interna anónima puede ser útil al hacer una instancia de un objeto con ciertos "extras", como anular métodos, sin tener que subclasificar una clase.
Tiendo a usarlo como atajo para adjuntar un detector de eventos:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
El uso de este método hace que la codificación sea un poco más rápida, ya que no necesito hacer una clase adicional que se implemente ActionListener
, solo puedo crear una instancia de una clase interna anónima sin hacer una clase separada.
Solo uso esta técnica para tareas "rápidas y sucias" en las que hacer que una clase entera se sienta innecesaria. Tener múltiples clases internas anónimas que hacen exactamente lo mismo debe refactorizarse a una clase real, ya sea una clase interna o una clase separada.
overloading methods
y no overriding methods
?
Las clases internas anónimas son cierres efectivos, por lo que pueden usarse para emular expresiones lambda o "delegados". Por ejemplo, tome esta interfaz:
public interface F<A, B> {
B f(A a);
}
Puede usar esto de forma anónima para crear una función de primera clase en Java. Digamos que tiene el siguiente método que devuelve el primer número más grande que i en la lista dada, o i si ningún número es mayor:
public static int larger(final List<Integer> 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 i en la lista dada, o i si ningún número es más pequeño:
public static int smaller(final List<Integer> 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 reescribirlas en un método de la siguiente manera:
public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
for (T t : ts)
if (f.f(t))
return t;
return z;
}
Puede usar una clase anónima para usar el método firstMatch:
F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
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 programación hacer esto" por el propio Joel.
Una buena biblioteca para programar Java en este estilo: Java funcional.
La clase interna anónima se utiliza en el siguiente escenario:
1.) Para la anulación (subclasificación), cuando la definición de clase no se puede utilizar, 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 la implementación de la interfaz se requiere 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");
}
});
}
}
A veces los uso como un truco de sintaxis para la creación de instancias de mapas:
Map map = new HashMap() {{
put("key", "value");
}};
vs
Map map = new HashMap();
map.put("key", "value");
Ahorra algo de redundancia al hacer muchas declaraciones put. Sin embargo, también he tenido problemas para hacer esto cuando la clase externa necesita ser serializada a través de comunicación remota.
Se usan comúnmente como una forma detallada de devolución de llamada.
Supongo que se podría decir que son una ventaja en comparación con no tenerlos y tener que crear una clase con nombre cada vez, pero 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 desordenadamente detallado, es mucho mejor que forzarlo 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)
myButton.addActionListener(e -> { /* do stuff here */})
o myButton.addActionListener(stuff)
sería terser.
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 generar un hilo), etc.
La idea es que los llame desde dentro del código de una función para que nunca se refiera a ellos en otro lugar, por lo que no necesita nombrarlos. El compilador solo los enumera.
Son esencialmente azúcares sintácticos, y generalmente deben trasladarse a otro lugar a medida que crecen.
No estoy seguro de si es una de las ventajas de Java, aunque si los usa (y todos los usamos con frecuencia, desafortunadamente), podría argumentar que son uno.
Lineamientos para la clase anónima.
La clase anónima se declara e inicializa simultáneamente.
La clase anónima debe extenderse o implementarse a una y solo una clase o interfaz resp.
Como la clase anónima 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
}
});
ref.getClass().newInstance()
.
Sí, las clases internas anónimas son definitivamente una de las ventajas de Java.
Con una clase interna anónima, tiene acceso a las variables finales y miembros de la clase circundante, y eso es útil para los oyentes, etc.
Pero una ventaja importante es que el código de la clase interna, que (al menos debería estar) estrechamente acoplado a la clase / método / bloque circundante, tiene un contexto específico (la clase, el método y el bloque circundantes).
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
Yo uso objetos anónimos para llamar nuevos hilos.
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
Una clase interna está asociada con una instancia de la clase externa y hay dos clases especiales: clase local y clase anónima . Una clase anónima nos permite declarar e instanciar 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 Person
clase:
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<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
donde CheckPerson
hay una interfaz como:
interface CheckPerson {
boolean test(Person p);
}
Ahora podemos hacer uso de la 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 sintaxis 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 un solo método abstracto, por lo tanto, podemos decir que CheckPerson
es una interfaz funcional. Podemos hacer uso de la expresión Lambda 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 usar una interfaz funcional estándar Predicate
en lugar de la interfaz CheckPerson
, lo que reducirá aún más la cantidad de código requerido.
La clase interna anónima puede ser beneficiosa al proporcionar diferentes implementaciones para diferentes objetos. Pero debe usarse con moderación, ya que crea un problema para la legibilidad del programa.
Uno de los principales usos de las clases anónimas en la finalización de clase que se llama guardián finalizador . En el mundo Java, debe evitarse el uso de los métodos de finalización hasta que realmente los necesite. Debe recordar que cuando anula el método de finalización para subclases, siempre debe invocar super.finalize()
también, porque el método de finalización de superclase no invocará automáticamente y puede tener problemas con pérdidas de memoria.
considerando el hecho mencionado anteriormente, puede 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 se alivió a sí mismo y a sus otros desarrolladores para recurrir super.finalize()
a cada subclase del HeavyClass
método que necesita finalizar.
Parece que nadie mencionó aquí, pero también puede usar una clase anónima para mantener el argumento de tipo genérico (que normalmente se pierde debido a la eliminación de tipo) :
public abstract class TypeHolder<T> {
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 crea una instancia de esta clase de forma anónima
TypeHolder<List<String>, Map<Ineger, Long>> holder =
new TypeHolder<List<String>, Map<Ineger, Long>>() {};
entonces dicha holder
instancia contendrá una definición no borrada del tipo pasado.
Esto es muy útil para construir validadores / deserializadores. También puede crear instancias de tipo genérico con reflexión (por lo que si alguna vez ha querido hacerlo new T()
en tipo parametrizado, ¡de nada !) .
La mejor manera de optimizar el código. Además, podemos utilizar 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 usa para crear un objeto al que nunca se hará referencia nuevamente. No tiene nombre y se declara y crea en la misma declaración. Esto se usa donde normalmente usaría la variable de un objeto. Reemplaza la variable con la new
palabra clave, una llamada a un constructor y la definición de clase dentro {
y }
.
Al escribir un programa de subprocesos en Java, generalmente 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 Runnable
interfaz que se requiere para crear hilos. En el ThreadClass
el run()
método (sólo método en Runnable
) necesita ser implementado también. Está claro que deshacerse de ThreadClass
él sería más eficiente y es exactamente por eso que 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 task
en el ejemplo más superior. En lugar de tener una clase separada, la clase interna anónima dentro del Thread()
constructor devuelve un objeto sin nombre que implementa la Runnable
interfaz y anula el run()
método. El método run()
incluiría declaraciones dentro que hacen el trabajo requerido por el hilo.
Respondiendo a la pregunta sobre si las clases internas anónimas son una de las ventajas de Java, tendría que decir que no estoy muy seguro ya que no estoy familiarizado con muchos lenguajes de programación en este momento. Pero lo que puedo decir es que definitivamente es un método de codificación más rápido y fácil.
Referencias: Sams Teach Yourself Java en 21 días Séptima edición