son - ¿Cómo se usan las clases anónimas(internas) en Java?
que es una interfaz interna (18)
Líneas de guía para la clase anónima.
La clase anónima se declara y se inicializa simultáneamente.
La clase anónima debe extenderse o implementarse en una y solo una clase o interfaz resp.
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
}
});
¿Cuál es el uso de clases anónimas en Java? ¿Podemos decir que el uso de la clase anónima es una de las ventajas de Java?
La clase interna anónima puede ser beneficiosa al dar diferentes implementaciones para diferentes objetos. Pero debe usarse con moderación, ya que crea problemas para la legibilidad del programa.
La clase interna anónima se usa en el siguiente escenario:
1.) Para anular (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 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 en 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");
}
});
}
}
La mejor manera de optimizar el código. También, podemos usar para un método de reemplazo 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();
}
}
Las clases internas anónimas son efectivamente cierres, por lo que pueden utilizarse para emular expresiones lambda o "delegados". Por ejemplo, toma esta interfaz:
public interface F<A, B> {
B f(A a);
}
Puede usar esto anónimamente 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 más grande:
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
Y luego tienes 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 el tipo de función F de primera clase, podemos reescribirlos 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;
}
Puedes 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 muy útil. Consulte "¿Puede su lenguaje de programación hacer esto" por el mismo Joel?
Una buena biblioteca para programar Java en este estilo: Java funcional.
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 el interior del código de una función para que nunca los consulte en otro lugar, por lo que no es necesario que los nombre. El compilador simplemente los enumera.
Son esencialmente azúcar sintáctica y, por lo general, deberían 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 una.
Los uso a veces 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");
Se ahorra algo de redundancia cuando se hacen muchas declaraciones de venta. Sin embargo, también me he encontrado con problemas al hacer esto cuando la clase externa necesita ser serializada a través de la comunicación remota.
Parece que nadie se menciona aquí, pero también puedes usar una clase anónima para mantener un argumento de tipo genérico (que normalmente se pierde debido al borrado 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 va a crear 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 instancia de holder
contendrá una definición no borrada del tipo pasado.
Uso
Esto es muy útil para la construcción de validadores / deserializadores. También puede crear una instancia del tipo genérico con reflexión (por lo tanto, si alguna vez quiso hacer una new T()
en tipo parametrizado, ¡bienvenido!) .
Inconvenientes / Limitaciones
- Debes pasar el parámetro genérico explícitamente. De no hacerlo, se producirá una pérdida de parámetros de tipo.
- Cada creación de instancias le costará una clase adicional para ser generada por el compilador, lo que conduce a la contaminación de la ruta de clase / jarra
Por una "clase anónima", entiendo que se refiere a la clase interna anónima .
Una clase interna anónima puede ser útil cuando se crea una instancia de un objeto con ciertos "extras" como los métodos de anulación, sin tener que subclasificar una clase.
Tiendo a usarlo como acceso directo 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 crear una clase adicional que 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" donde hacer que una clase entera se sienta innecesaria. Tener varias clases internas anónimas que hacen exactamente lo mismo debe ser refactorizado a una clase real, ya sea una clase interna o una clase separada.
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);
}
});
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 ventaja importante es que el código de clase interno, que está (al menos debería estar) estrechamente unido a la clase / método / bloque circundante, tiene un contexto específico (la clase, el método y el bloque circundantes).
Se utiliza una clase interna anónima para crear un objeto al que nunca se volverá a hacer referencia. No tiene nombre y está declarado y creado en la misma declaración. Esto se usa donde normalmente usarías 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 de {
y }
.
Cuando se escribe un Programa Threaded en Java, normalmente se vería así
ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();
El ThreadClass
usado aquí sería definido por el usuario. Esta clase implementará la interfaz Runnable
que se requiere para crear subprocesos. En la ThreadClass
el método run()
(solo el método en Runnable
) también debe implementarse. Está claro que deshacerse de ThreadClass
sería más eficiente y esa es la razón por la 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 a la task
en el ejemplo más destacado. 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 reemplaza el método run()
. El método run()
incluiría sentencias internas que realizan el trabajo requerido por el hilo.
Responder a la pregunta sobre si las Clases internas anónimas es una de las ventajas de Java, debo 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
Se utilizan comúnmente como una forma verbosa de devolución de llamada.
Supongo que podría decir que son una ventaja en comparación con no tenerlos y tener que crear una clase con nombre cada vez, 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 un poco detallado, es mucho mejor que forzarlo a definir una clase con nombre para cada oyente desechado de esta manera (aunque dependiendo de la situación y la reutilización, ese puede ser el mejor enfoque)
Una clase interna está asociada 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 una instancia 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 del doc donde tenemos una clase de 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<Person> 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 la clase anónima que implementa esta interfaz para especificar los 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 no está clara.
Java 8 ha introducido un término Interfaz funcional que es una interfaz con un solo método abstracto, por lo que podemos decir que CheckPerson
es una interfaz funcional. Podemos hacer uso de doc que nos permite pasar la función como argumento del método como:
printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
Podemos usar un Predicate
interfaz funcional estándar en lugar de la interfaz CheckPerson
, lo que reducirá aún más la cantidad de código requerido.
Una ventaja más:
Como sabe, Java no admite la herencia múltiple, por lo tanto, si utiliza la clase "Thread" como clase anónima, a la clase todavía le queda un espacio para que se extienda cualquier otra clase.
Uno de los principales usos de las clases anónimas en la finalización de la clase que llamó finalizer guardian . En el mundo Java, se deben evitar los métodos de finalización hasta que realmente los necesites. Debe recordar que cuando anula el método de finalización para las subclases, siempre debe invocar también super.finalize()
, ya que el método de finalización de la super.finalize()
no se invoca automáticamente y puede tener problemas con las pérdidas de memoria.
así que, considerando 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 se liberó a sí mismo ya sus otros desarrolladores para llamar a super.finalize()
en cada subclase de HeavyClass
que necesita un método de finalización.
Yo uso objetos anónimos para llamar nuevos hilos ..
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
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 utiliza subprocesos.