2009-06-22 7 views
17

¿Las clases internas se usan comúnmente en Java? ¿Son estos lo mismo que las clases anidadas? ¿O han sido reemplazados en Java por algo mejor? Tengo un libro sobre la versión 5 y tiene un ejemplo usando una clase interna, pero pensé que leí que algunas clases internas eran "malas".¿Las clases internas se usan comúnmente en Java? ¿Son ellos "malos"?

No tengo ni idea y esperaba ideas al respecto.

Gracias.

+0

http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class –

+2

"Terminología: las clases anidadas se dividen en dos categorías: estáticas y no estáticas. Clases anidadas que son declaradas estáticas simplemente se llaman clases anidadas estáticas. Las clases anidadas no estáticas se llaman clases internas ". - De http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

+0

Posible duplicado http://stackoverflow.com/questions/487126/is-usage-of-anonymous-classes -in-java-considered-bad-style-or-good –

Respuesta

28

Las clases internas se utilizan con frecuencia, y algo muy similar, las clases anónimas, son prácticamente indispensables, ya que son lo más parecido a Java que tiene que cerrarse. Entonces, si no puedes recordar dónde oíste que las clases internas son malas, ¡trata de olvidarlo!

+1

simplemente no mencione los inicializadores de doble llave ... – skaffman

+0

Los cierres básicamente permiten que un fragmento de código se envíe a otra parte, y aún se refieren a su entorno original. Puede ser muy, muy agradable. –

+2

@skaffman - ¡ack! Solo los miré, no pude creerlo. ¿Crees que has creado una lista ? Adivina de nuevo, mi amigo, ¡adivina otra vez! –

3

No creo que sean malas o malas. Tal vez no sean ampliamente utilizados, pero tienen muchos usos, las devoluciones de llamadas son uno de ellos. Una ventaja especial es que pueden extenderse desde una clase diferente a la clase externa, por lo que podría tener herencia múltiple.

Diría que uno de los problemas con las clases internas es que su sintaxis es algo "fea". Eso es algo que desalienta a algunas personas. Aquí en el trabajo hay muchos de ellos.

16

No son "malas" como tales.

Pueden estar sujetos a abuso (clases internas de clases internas, por ejemplo). Tan pronto como mi clase interna abarque más que unas pocas líneas, prefiero extraerla en su propia clase. Ayuda a la legibilidad y prueba en algunos casos.

Hay un gotcha que no es inmediatamente obvio, y vale la pena recordarlo. Cualquier clase interna que no sea static tendrá una referencia implícita a la clase externa circundante (una referencia 'this' implícita). Esto normalmente no es un problema, pero si vienes a serializar la clase interna (digamos, usando XStream), encontrarás que esto puede causarte un dolor inesperado.

1

Son útiles y pueden usarse con mucha frecuencia. Si bien debes tener cuidado al abusar de la funcionalidad, no son mucho más propensos a ser abusados ​​que cualquier otra característica del idioma.

2

Un buen ejemplo de una clase interna es la implementación del iterador para un tipo de colección dado. Es una clase que implementa una interfaz pública, pero no tiene ningún negocio existente excepto en asociación con otra clase. Te permite modelar cosas que en C++ te obligarían a hacer con el operador amigo.

2

Las clases internas no estáticas pueden ocultar un problema de rendimiento. Tienen acceso a los campos de miembros en la clase adjunta, pero no directamente, sino a través de getters que se crean automáticamente. Esto será más lento que simplemente copiar a los miembros de la clase adjunta a la clase interna.

Algunos otros problemas con las clases internas no estáticos se describen here

0

La clave para recordar es que usted va a la flexibilidad de la simplicidad y la cohesión comercio al hacer las dos clases más estrechamente unidas. Puede querer que las clases estén estrechamente vinculadas, pero está renunciando a la capacidad de intercambiar de forma transparente otras clases en lugar de lo que actualmente es su clase incrustada al no definir su clase desde una interfaz fuera de la clase contenedora.

0

Considere siguiente ejemplo:

public class OuterClass { 

private AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass() { 
    @Override 
    protected void printAboutme() { 
     System.out.println("AnonymousInnerClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
}; 

public void displayAnonymousInnerClass() { 
    anonymousInnerClass.printAboutme(); 
} 

public void displayStaticInnerClass() { 
    NestedStaticClass staticInnerClass = new NestedStaticClass(); 
    staticInnerClass.printAboutMe(); 
} 

public void displayInnerClass() { 
    InnerClass innerClass = new InnerClass(); 
    innerClass.printAboutMe(); 
} 

public void displayMethodInnerClass(){ 

    class MethodInnerClass { 

     private String sampleField = "Method Inner Class"; 
     public void printAboutMe() { 
      System.out.println("MethodInnerClass.printAboutMe........."); 
      Class clazz = this.getClass(); 

      Field[] fields = clazz.getDeclaredFields(); 
      for (Field field : fields) { 

       String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
       message = message + " " + field.getType().getSimpleName(); 
       message = message + " " + field.getName(); 

       System.out.println(message); 
      } 
     } 
    } 

    MethodInnerClass methodInnerClass = new MethodInnerClass(); 
    methodInnerClass.printAboutMe(); 
} 

class InnerClass { 
    private String sampleField = "Inner Class"; 
    public void printAboutMe() { 
     System.out.println("InnerClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
} 


abstract class AnonymousInnerClass { 
    protected String sampleField = "Anonymous Inner Class"; 
    protected abstract void printAboutme(); 
} 

static class NestedStaticClass { 
    private String sampleField = "NestedStaticClass"; 
    public void printAboutMe() { 
     System.out.println("NestedStaticClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
} 

}

en este ejemplo no hay comparación de cada tipo de clase anidada estática no con class.Now anidada estática si se ejecuta el método de visualización de la clase externa para cada clase anidada verá la salida de cada clase anidada método printAboutMe(), que tiene un código de reflexión para imprimir todas las variables miembro de las clases anidadas.

Verá que para las clases no anidadas hay una variable de miembro adicional distinta de la cadena de variable declarada en el código, que solo está presente en el tiempo de ejecución.

por ejemplo si ejecutamos el siguiente código para InnerClass. : -

public class NestedClassesDemo { 

public static void main(String[] args) { 
    OuterClass outerClass = new OuterClass(); 
    outerClass.displayInnerClass(); 
} 

}

salida es la siguiente: -

InnerClass.printAboutMe......... 
private String sampleField 
protected OuterClass this$0 

en cuenta que es variable miembro misterio esta clase $ 0 de tipo envolvente (clase externa).

Ahora ya está claro que las clases internas mantienen referencia a la imagen externa escenario class.So por donde sale la referencia de clase interna a otra clase de mundo exterior y luego hacer referencia no se libera a su vez OuterClass también se refiere, por lo tanto, tener fugas.

Esto hace que el uso de clases internas sea malo si no se usa por primera vez.

No existe este caso con clases internas estáticas.Por favor, ejecute todos los métodos de visualización.También si algún problema en el código, por favor, señalar.

+1

'Static inner' es una [contradicción en términos] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3), y 'non- estático anidado 'puede ser reemplazado por' interno '. – EJP

Cuestiones relacionadas