Pregunta

Estaba mirando el código de Java para LinkedList y noté que hacía uso de una clase anidada estática, Entry .

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

¿Cuál es la razón para usar una clase anidada estática, en lugar de una clase interna normal?

La única razón por la que pude pensar fue que Entry no tiene acceso a las variables de instancia, por lo que desde un punto de vista OOP tiene una mejor encapsulación.

Pero pensé que podría haber otras razones, tal vez el rendimiento. ¿Qué podría ser?

Nota. Espero haber definido correctamente mis términos, lo habría llamado una clase interna estática, pero creo que esto es incorrecto: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

¿Fue útil?

Solución

La página de Sun a la que te vinculas tiene algunas diferencias clave entre las dos:

  

Una clase anidada es un miembro de su clase adjunta. Las clases anidadas no estáticas (clases internas) tienen acceso a otros miembros de la clase adjunta, incluso si se declaran privadas. Las clases anidadas estáticas no tienen acceso a otros miembros de la clase adjunta.
  ...

     

Nota: una clase anidada estática interactúa con los miembros de instancia de su clase externa (y otras clases) al igual que cualquier otra clase de nivel superior. En efecto, una clase anidada estática es conductualmente una clase de nivel superior que se ha anidado en otra clase de nivel superior para la conveniencia de empaquetado.

No es necesario que LinkedList.Entry sea una clase de nivel superior, ya que es solo utilizado por LinkedList (hay otros interfaces que también tienen clases anidadas estáticas llamadas Entry , como Map.Entry - mismo concepto). Y como no necesita acceso a los miembros de LinkedList, tiene sentido que sea estático: es un enfoque mucho más limpio.

Como señala Jon Skeet , creo que es una mejor idea si está utilizando una clase anidada. desactivado, ya que es estático, y luego decidir si realmente necesita ser no estático en función de su uso.

Otros consejos

En mi opinión, la pregunta debería ser al revés cada vez que veas una clase interna. ¿Realmente realmente tiene que ser una clase interna, con la complejidad adicional y lo implícito (en lugar de ¿Referencia explícita y más clara, a una instancia de la clase contenedora?

Eso sí, estoy predispuesto como fanático de C #: C # no tiene el equivalente de clases internas, aunque sí tiene tipos anidados. No puedo decir que me haya perdido clases internas :)

Hay problemas de retención de memoria no obvios que se deben tener en cuenta aquí. Dado que una clase interna no estática mantiene una referencia implícita a su clase 'externa', si se hace referencia a una instancia de la clase interna, entonces también se hace referencia a la instancia externa. Esto puede llevar a que se rasque la cabeza cuando la clase externa no es recogida de basura, a pesar de que aparece que nada hace referencia a ella.

Bueno, para empezar, las clases internas no estáticas tienen un campo oculto adicional que apunta a la instancia de la clase externa. Entonces, si la clase Entrada no fuera estática, además de tener acceso que no necesita, llevaría alrededor de cuatro punteros en lugar de tres.

Como regla general, diría que si define una clase que está básicamente allí para actuar como una colección de miembros de datos, como una estructura " struct " en C, considera hacerlo estático.

la clase anidada estática es como cualquier otra clase externa, ya que no tiene acceso a los miembros de la clase externa.

Sólo por conveniencia de empaquetado, podemos agrupar las clases anidadas estáticas en una clase externa para facilitar la lectura. Aparte de esto, no hay otro caso de uso de la clase anidada estática.

Ejemplo de este tipo de uso, puede encontrarlo en el archivo R.java (recursos) de Android. La carpeta Res de android contiene diseños (que contienen diseños de pantalla), una carpeta dibujable (que contiene imágenes utilizadas para el proyecto), una carpeta de valores (que contiene constantes de cadena), etc.

Sine todas las carpetas son parte de la carpeta Res, la herramienta Android genera un archivo R.java (recursos) que internamente contiene muchas clases anidadas estáticas para cada una de sus carpetas internas.

Este es el aspecto del archivo R.java generado en Android: Aquí se están utilizando sólo para la conveniencia de embalaje.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}

La clase interna estática se usa en el patrón de construcción. La clase interna estática puede crear una instancia de su clase externa que solo tiene constructor privado. Por lo tanto, puede usar la clase interna estática para crear una instancia de la clase externa que solo tiene un constructor privado. No puede hacer lo mismo con la clase interna, ya que necesita tener un objeto de la clase externa creado antes de acceder a la clase interna.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

Esto generará x: 1

De http://docs.oracle.com/javase/tutorial /java/javaOO/whentouse.html :

  

Use una clase anidada no estática (o clase interna) si necesita acceso   a los campos y métodos no públicos de una instancia adjunta. Usa una estática   clase anidada si no requiere este acceso.

Ejemplo simple:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Si no es estático, no se puede crear una instancia de la clase, excepto en una instancia de la clase superior (por lo tanto, no en el ejemplo donde main es una función estática)

Una de las razones de estática y normal tiene que ver con la carga de clases. No puede crear una instancia de una clase interna en el constructor de su padre.

PS: Siempre he entendido que 'anidado' e 'interno' son intercambiables. Puede haber matices sutiles en los términos, pero la mayoría de los desarrolladores de Java lo entenderían.

Las clases internas no estáticas pueden provocar pérdidas de memoria, mientras que las clases internas estáticas protegen contra ellas. Si la clase externa contiene datos considerables, puede disminuir el rendimiento de la aplicación.

No sé acerca de la diferencia de rendimiento, pero como usted dice, la clase anidada estática no es parte de una instancia de la clase envolvente. Parece más simple crear una clase anidada estática a menos que realmente necesites que sea una clase interna.

Es un poco como por qué siempre hago que mis variables sean definitivas en Java: si no son definitivas, sé que hay algo raro en ellas. Si utiliza una clase interna en lugar de una clase anidada estática, debería haber una buena razón.

El uso de una clase anidada estática en lugar de una no estática puede ahorrar espacios en algunos casos. Por ejemplo: implementando un Comparator dentro de una clase, diga Estudiante.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Luego, static garantiza que la clase de estudiantes tenga solo un comparador, en lugar de crear una instancia cada vez que se cree una nueva instancia de estudiante.

Adavantage of inner class--

  1. uso único
  2. admite y mejora la encapsulación
  3. legibilidad
  4. acceso de campo privado

Sin que exista una clase externa, la clase interna no existirá.

class car{
    class wheel{

    }
}

Hay cuatro tipos de clases internas.

  1. clase interna normal
  2. Método de clase interna local
  3. Clase interna anónima
  4. clase interna estática

punto ---

  1. de la clase interna estática, solo podemos acceder al miembro estático de la clase externa.
  2. Dentro de la clase interna no podemos declarar miembro estático.
  3. para invocar una clase interna normal en el área estática de la clase externa.

    Outer 0 = new Outer (); Outer.Inner i = O.new Inner ();

  4. para invocar una clase interna normal en el área de instancia de la clase externa.

    Inner i = new Inner ();

  5. para invocar una clase interna normal fuera de la clase externa.

    Outer 0 = new Outer (); Outer.Inner i = O.new Inner ();

  6. dentro de la clase interna Este puntero a la clase interna.

    this.member-current clase interna outerclassname.this - clase externa

  7. para el modificador aplicable de clase interna es - público, predeterminado,

    final,abstract,strictfp,+private,protected,static

  8. externo $ inner es el nombre del nombre interno de la clase.

  9. clase interna dentro del método de instancia, entonces podemos acceder al campo estático y de instancia de la clase externa.

10. clase interna dentro del método estático, entonces podemos acceder solo al campo estático de

clase externa.

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top