Pregunta

¿Cuál es la principal diferencia entre una clase interna y una clase anidada estática en Java?¿El diseño/implementación influye en la elección de uno de ellos?

¿Fue útil?

Solución

Desde el Tutorial de Java:

Las clases anidadas se dividen en dos categorías:estática y no estática.Las clases anidadas que se declaran estáticas se denominan simplemente clases anidadas estáticas.Las clases anidadas no estáticas se denominan clases internas.

Se accede a las clases anidadas estáticas utilizando el nombre de clase adjunto:

OuterClass.StaticNestedClass

Por ejemplo, para crear un objeto para la clase anidada estática, utilice esta sintaxis:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Los objetos que son instancias de una clase interna existen dentro de una instancia de la clase externa.Considere las siguientes clases:

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

Una instancia de InnerClass sólo puede existir dentro de una instancia de OuterClass y tiene acceso directo a los métodos y campos de su instancia adjunta.

Para crear una instancia de una clase interna, primero debe crear una instancia de la clase externa.Luego, crea el objeto interno dentro del objeto externo con esta sintaxis:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

ver: Tutorial de Java: clases anidadas

Para completar, tenga en cuenta que también existe algo llamado clase interna sin una instancia adjunta:

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

Aquí, new A() { ... } es un clase interna definida en un contexto estático y no tiene una instancia adjunta.

Otros consejos

El El tutorial de Java dice:

Terminología:Las clases anidadas se dividen en dos categorías:estático y no estático.Las clases anidadas que se declaran estáticas se llaman simplemente clases estáticas anidadas.Las clases anidadas no estáticas se llaman clases internas.

En el lenguaje común, la mayoría de los programadores usan indistintamente los términos "anidado" e "interno", pero usaré el término correcto "clase anidada" que cubre tanto interno como estático.

Las clases se pueden anidar. indefinidamente, p.ej.la clase A puede contener la clase B que contiene la clase C que contiene la clase D, etc.Sin embargo, es raro que haya más de un nivel de anidamiento de clases, ya que generalmente es un mal diseño.

Hay tres razones por las que podrías crear una clase anidada:

  • organización:A veces parece más sensato ordenar una clase en el espacio de nombres de otra clase, especialmente cuando no se usará en ningún otro contexto.
  • acceso:las clases anidadas tienen acceso especial a las variables/campos de sus clases contenedoras (precisamente qué variables/campos dependen del tipo de clase anidada, ya sea interna o estática).
  • conveniencia:tener que crear un nuevo archivo para cada nuevo tipo es molesto, nuevamente, especialmente cuando el tipo solo se usará en un contexto

Hay cuatro tipos de clases anidadas en Java.En resumen, son:

  • clase estática:declarado como miembro estático de otra clase
  • clase interna:declarado como miembro de instancia de otra clase
  • clase interna local:declarado dentro de un método de instancia de otra clase
  • clase interna anónima:como una clase interna local, pero escrita como una expresión que devuelve un objeto único

Déjame explicarte con más detalles.


Clases estáticas

Las clases estáticas son las más fáciles de entender porque no tienen nada que ver con instancias de la clase contenedora.

Una clase estática es una clase declarada como miembro estático de otra clase.Al igual que otros miembros estáticos, dicha clase es en realidad solo un colgador que utiliza la clase contenedora como su espacio de nombres. p.ej. la clase Cabra declarado como miembro estático de la clase Rinoceronte en el paquete pizza es conocido por el nombre pizza.Rhino.Cabra.

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Francamente, las clases estáticas son una característica bastante inútil porque las clases ya están divididas en espacios de nombres por paquetes.La única razón real concebible para crear una clase estática es que dicha clase tenga acceso a los miembros estáticos privados de la clase que la contiene, pero encuentro que esto es una justificación bastante poco convincente para que exista la característica de clase estática.


clases internas

Una clase interna es una clase declarada como miembro no estático de otra clase:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Al igual que con una clase estática, la clase interna se conoce como calificada por el nombre de la clase que la contiene, pizza.Rhino.Cabra, pero dentro de la clase que lo contiene, se puede conocer por su simple nombre.Sin embargo, cada instancia de una clase interna está vinculada a una instancia particular de su clase contenedora:sobre el Cabra creado en alemán, está implícitamente ligado a la Rinoceronte instancia este en alemán.En caso contrario, realizamos el asociado Rinoceronte instancia explícita cuando creamos una instancia Cabra:

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(Observe que se refiere al tipo interno simplemente como Cabra en lo raro nuevo sintaxis:Java infiere el tipo contenedor a partir del rinoceronte parte.Y si nuevo rinoceronte.Cabra() habría tenido más sentido para mí también).

Entonces, ¿qué nos aporta esto?Bueno, la instancia de clase interna tiene acceso a los miembros de la instancia de clase contenedora.Se hace referencia a estos miembros de instancia adjuntos dentro de la clase interna. a través de sólo sus nombres simples, no a través de este (este en la clase interna se refiere a la instancia de la clase interna, no a la instancia de la clase contenedora asociada):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

En la clase interna, puede consultar este de la clase contenedora como Rhino.este, y puedes usar este para referirse a sus miembros, p.ej.Rhino.este.barry.


Clases internas locales

Una clase interna local es una clase declarada en el cuerpo de un método.Dicha clase solo se conoce dentro de su método contenedor, por lo que solo se puede crear una instancia de ella y acceder a sus miembros dentro de su método contenedor.La ganancia es que una instancia de clase interna local está vinculada y puede acceder a las variables locales finales de su método contenedor.Cuando la instancia usa un local final de su método contenedor, la variable retiene el valor que tenía en el momento de la creación de la instancia, incluso si la variable ha salido del alcance (esta es efectivamente la versión tosca y limitada de cierres de Java).

Debido a que una clase interna local no es miembro de una clase o paquete, no se declara con un nivel de acceso.(Sin embargo, tenga claro que sus propios miembros tienen niveles de acceso como en una clase normal).

Si se declara una clase interna local en un método de instancia, una instanciación de la clase interna está vinculada a la instancia mantenida por el método contenedor. este en el momento de la creación de la instancia, por lo que se puede acceder a los miembros de la instancia de la clase contenedora como en una clase interna de la instancia.Se crea una instancia de una clase interna local simplemente a través de su nombre, p.ej. clase interna local Gato se instancia como nuevo gato(), no nuevo this.Cat() como era de esperar.


Clases internas anónimas

Una clase interna anónima es una forma sintácticamente conveniente de escribir una clase interna local.Por lo general, se crea una instancia de una clase interna local como máximo una vez cada vez que se ejecuta su método contenedor.Sería bueno, entonces, si pudiéramos combinar la definición de clase interna local y su instanciación única en una forma de sintaxis conveniente, y también sería bueno si no tuviéramos que pensar en un nombre para la clase (cuanto menos inútil sea). nombres que contenga su código, mejor).Una clase interna anónima permite ambas cosas:

new *ParentClassName*(*constructorArgs*) {*members*}

Esta es una expresión que devuelve una nueva instancia de una clase sin nombre que se extiende Nombre de clase principal.No puedes suministrar tu propio constructor;más bien, se proporciona implícitamente uno que simplemente llama al superconstructor, por lo que los argumentos proporcionados deben ajustarse al superconstructor.(Si el padre contiene múltiples constructores, el “más simple” se llama, “el más simple” según lo determina un conjunto bastante complejo de reglas que no vale la pena aprender en detalle; solo preste atención a lo que NetBeans o Eclipse le dicen).

Alternativamente, puede especificar una interfaz para implementar:

new *InterfaceName*() {*members*}

Tal declaración crea una nueva instancia de una clase sin nombre que extiende el Objeto e implementa Nombre de la interfaz.Nuevamente, no puede suministrar su propio constructor;en este caso, Java proporciona implícitamente un constructor sin argumentos y que no hace nada (por lo que nunca habrá argumentos de constructor en este caso).

Aunque no puedes darle un constructor a una clase interna anónima, aún puedes hacer cualquier configuración que quieras usando un bloque inicializador (un bloque {} colocado fuera de cualquier método).

Tenga claro que una clase interna anónima es simplemente una forma menos flexible de crear una clase interna local con una instancia.Si desea una clase interna local que implemente múltiples interfaces o que implemente interfaces mientras extiende alguna clase que no sea Objeto o que especifica su propio constructor, estás atascado creando una clase interna local con nombre normal.

No creo que la diferencia real quedó clara en las respuestas anteriores.

Primero en entender bien los términos:

  • Una clase anidada es una clase contenida en otra clase en el nivel del código fuente.
  • Es estático si lo declaras con el estático modificador.
  • Una clase anidada no estática se llama clase interna.(Me quedo con la clase anidada no estática).

La respuesta de Martin es correcta hasta ahora.Sin embargo, la pregunta real es:¿Cuál es el propósito de declarar estática o no una clase anidada?

Tu usas clases anidadas estáticas si solo desea mantener sus clases juntas si pertenecen juntas por temas o si la clase anidada se usa exclusivamente en la clase adjunta.No existe una diferencia semántica entre una clase anidada estática y cualquier otra clase.

Clases anidadas no estáticas son una bestia diferente.Al igual que las clases internas anónimas, estas clases anidadas son en realidad cierres.Eso significa que capturan el alcance que los rodea y su instancia circundante y los hacen accesibles.Quizás un ejemplo aclare esto.Vea este fragmento de un contenedor:

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

En este caso, desea tener una referencia de un elemento secundario al contenedor principal.Al utilizar una clase anidada no estática, esto funciona sin mucho trabajo.Puede acceder a la instancia adjunta de Container con la sintaxis Container.this.

Más explicaciones duras a continuación:

Si observa los códigos de bytes de Java que genera el compilador para una clase anidada (no estática), podría resultar aún más claro:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Como puede ver, el compilador crea un campo oculto. Container this$0.Esto se establece en el constructor que tiene un parámetro adicional de tipo Contenedor para especificar la instancia adjunta.No puede ver este parámetro en el código fuente, pero el compilador lo genera implícitamente para una clase anidada.

El ejemplo de Martín

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

sería compilado en una llamada de algo como (en códigos de bytes)

new InnerClass(outerObject)

En aras de la exhaustividad:

Una clase anónima es un ejemplo perfecto de una clase anidada no estática que simplemente no tiene ningún nombre asociado y no se puede hacer referencia a ella más adelante.

Creo que ninguna de las respuestas anteriores le explica la diferencia real entre una clase anidada y una clase anidada estática en términos de diseño de aplicación:

Descripción general

Una clase anidada podría ser estático o no estático y en cada caso es una clase definida dentro de otra clase. Una clase anidada debería existir sólo para servir a la clase adjunta., si una clase anidada es útil para otras clases (no solo la adjunta), debe declararse como una clase de nivel superior.

Diferencia

Clase anidada no estática :está implícitamente asociado con la instancia adjunta de la clase contenedora, esto significa que es posible invocar métodos y acceder a variables de la instancia adjunta.Un uso común de una clase anidada no estática es definir una clase de Adaptador.

Clase anidada estática :no puede acceder a la instancia de la clase adjunta e invocar métodos en ella, por lo que debe usarse cuando la clase anidada no requiere acceso a una instancia de la clase adjunta.Un uso común de la clase anidada estática es implementar componentes del objeto externo.

Conclusión

Entonces, la principal diferencia entre los dos desde el punto de vista del diseño es: La clase anidada no estática puede acceder a la instancia de la clase contenedora, mientras que la estática no puede..

En términos simples, necesitamos clases anidadas principalmente porque Java no proporciona cierres.

Las clases anidadas son clases definidas dentro del cuerpo de otra clase adjunta.Son de dos tipos: estáticos y no estáticos.

Se tratan como miembros de la clase adjunta, por lo que puede especificar cualquiera de los cuatro especificadores de acceso: private, package, protected, public.No podemos darnos este lujo con las clases de alto nivel, que sólo pueden declararse public o paquete privado.

Las clases internas, también conocidas como clases sin pila, tienen acceso a otros miembros de la clase superior, incluso si se declaran privadas, mientras que las clases anidadas estáticas no tienen acceso a otros miembros de la clase superior.

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1 es nuestra clase interna estática y Inner2 Es nuestra clase interna la que no es estática.La diferencia clave entre ellos es que no se puede crear una Inner2 instancia sin un Exterior donde puedes crear un Inner1 objeto de forma independiente.

¿Cuándo usarías la clase interna?

Piensa en una situación en la que Class A y Class B están relacionados, Class B necesita acceder Class A miembros, y Class B está relacionado sólo con Class A.Las clases internas entran en escena.

Para crear una instancia de una clase interna, necesita crear una instancia de su clase externa.

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

o

OuterClass.Inner2 inner = new OuterClass().new Inner2();

¿Cuándo usarías la clase interna estática?

Definiría una clase interna estática cuando sepa que no tiene ninguna relación con la instancia de la clase adjunta/clase superior.Si su clase interna no usa métodos o campos de la clase externa, es solo una pérdida de espacio, así que hágala estática.

Por ejemplo, para crear un objeto para la clase anidada estática, utilice esta sintaxis:

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

La ventaja de una clase anidada estática es que no necesita un objeto de la clase contenedora/clase superior para funcionar.Esto puede ayudarle a reducir la cantidad de objetos que crea su aplicación en tiempo de ejecución.

Creo que la convención que se sigue generalmente es la siguiente:

  • clase estática dentro de una clase de alto nivel es un clase anidada
  • clase no estática dentro de una clase de alto nivel es un clase interna, que más tiene dos formas más:
    • clase local - clases con nombre declaradas dentro de un bloque como un método o cuerpo de constructor
    • clase anónima - clases sin nombre cuyas instancias se crean en expresiones y declaraciones

Sin embargo, pocos otros puntos para recordar son:

  • Las clases de nivel superior y las clases anidadas estáticas son semánticamente iguales excepto que en el caso de una clase anidada estática puede hacer referencia estática a campos/métodos estáticos privados de su clase externa [principal] y viceversa.

  • Las clases internas tienen acceso a las variables de instancia de la instancia adjunta de la clase externa [principal].Sin embargo, no todas las clases internas tienen instancias adjuntas; por ejemplo, las clases internas en contextos estáticos, como una clase anónima utilizada en un bloque inicializador estático, no las tienen.

  • La clase anónima de forma predeterminada extiende la clase principal o implementa la interfaz principal y no hay ninguna cláusula adicional para extender ninguna otra clase o implementar más interfaces.Entonces,

    • new YourClass(){}; medio class [Anonymous] extends YourClass {}
    • new YourInterface(){}; medio class [Anonymous] implements YourInterface {}

Siento que la pregunta más importante que queda abierta es ¿cuál usar y cuándo?Bueno, eso depende principalmente del escenario al que te enfrentes, pero leer la respuesta dada por @jrudolph puede ayudarte a tomar una decisión.

Aquí se muestran las diferencias y similitudes clave entre la clase interna de Java y la clase anidada estática.

¡Espero eso ayude!

clase interna

  • Puede acceder a la clase exterior tanto de instancia como estático métodos y campos
  • Asociado con instancia de clase adjunta así que para crear una instancia primero se necesita una instancia de clase externa (nota nuevo lugar de palabras clave):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • No puedo definir cualquier miembros estáticos sí mismo

  • No puedo tener Clase o Interfaz declaración

Clase anidada estática

  • No puede acceder clase exterior instancia métodos o campos

  • No asociado con ninguna instancia de clase adjunta Entonces para crear una instancia:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
    

Similitudes

  • Ambos clases internas puede acceder incluso campos y métodos privados de clase exterior
  • También el clase exterior tener acceso a campos y métodos privados de clases internas
  • Ambas clases pueden tener modificador de acceso privado, protegido o público.

¿Por qué utilizar clases anidadas?

Según la documentación de Oracle, hay varias razones (documentación completa):

  • Es una forma de agrupar lógicamente clases que sólo se utilizan en un lugar: Si una clase es útil sólo para otra clase, entonces es lógico incrustarla en esa clase y mantener las dos juntas.Anidar estas "clases auxiliares" hace que su paquete sea más ágil.

  • Aumenta la encapsulación: Considere dos clases de nivel superior, A y B, donde B necesita acceso a miembros de A que de otro modo serían declarados privados.Al ocultar la clase B dentro de la clase A, los miembros de A pueden declararse privados y B puede acceder a ellos.Además, el propio B puede ocultarse del mundo exterior.

  • Puede conducir a un código más legible y mantenible: Anidar clases pequeñas dentro de clases de nivel superior coloca el código más cerca de donde se usa.

Clase anidada:clase dentro de clase

Tipos:

  1. Clase anidada estática
  2. Clase anidada no estática [clase interna]

Diferencia:

Clase anidada no estática [clase interna]

En una clase anidada no estática, el objeto de la clase interna existe dentro del objeto de la clase externa.De modo que el miembro de datos de la clase externa sea accesible para la clase interna.Entonces, para crear un objeto de clase interna, primero debemos crear un objeto de clase externa.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

Clase anidada estática

En una clase anidada estática, el objeto de la clase interna no necesita el objeto de la clase externa, porque la palabra "estático" indica que no es necesario crear un objeto.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

Si desea acceder a x, escriba el siguiente método interno

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

La instancia de la clase interna se crea cuando se crea la instancia de la clase externa.Por lo tanto, los miembros y métodos de la clase interna tienen acceso a los miembros y métodos de la instancia (objeto) de la clase externa.Cuando la instancia de la clase externa sale del alcance, también las instancias de la clase interna dejan de existir.

La clase anidada estática no tiene una instancia concreta.Simplemente se carga cuando se usa por primera vez (al igual que los métodos estáticos).Es una entidad completamente independiente, cuyos métodos y variables no tienen ningún acceso a las instancias de la clase externa.

Las clases anidadas estáticas no están acopladas con el objeto externo, son más rápidas y no ocupan memoria de montón/pila, porque no es necesario crear una instancia de dicha clase.Por lo tanto, la regla general es intentar definir una clase anidada estática, con un alcance lo más limitado posible (privada >= clase >= protegida >= pública), y luego convertirla en clase interna (eliminando el identificador "estático") y aflojarla. el alcance, si es realmente necesario.

Hay una sutileza en el uso de clases estáticas anidadas que pueden resultar útiles en determinadas situaciones.

Mientras que los atributos estáticos se instientan antes de que la clase sea instanciada a través de su constructor, los atributos estáticos dentro de las clases estáticas anidadas no parecen ser instanciadas hasta después de que el constructor de la clase sea invocado, o al menos no hasta que se mencionen los atributos, incluso si Están marcados como 'finales'.

Considere este ejemplo:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

Aunque tanto 'nested' como 'innerItem' se declaran como 'estático final'.La configuración de Nested.inneritem no se lleva a cabo hasta después de que la clase se instancia (o al menos no hasta que se hace referencia al ítem estático anidado), como puede ver por sí mismo comentando e incommentando las líneas a las que me refiero, arriba.Lo mismo no se mantiene verdadero para 'Outeritem'.

Al menos esto es lo que veo en Java 6.0.

En el caso de la creación de instancias, la instancia de la clase interna no estática se crea con la referencia del objeto de la clase externa en la que se define.Esto significa que tiene una instancia de inclinación.Pero la instancia de la clase interna estática se crea con la referencia de la clase externa, no con la referencia del objeto de la clase externa.Esto significa que no tiene una instancia de inclinación.

Por ejemplo:

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String… str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}

No creo que haya mucho que agregar aquí, la mayoría de las respuestas explican perfectamente las diferencias entre clases anidadas estáticas y clases internas.Sin embargo, considere el siguiente problema al utilizar clases anidadas frente a clases internas.Como se menciona en un par de respuestas, no se pueden crear instancias de clases internas sin una instancia de su clase adjunta, lo que significa que SOSTENER a puntero a la instancia de su clase adjunta, lo que puede provocar un desbordamiento de memoria o una excepción de desbordamiento de pila debido a que el GC no podrá recolectar basura de las clases adjuntas incluso si ya no se usan.Para que esto quede claro, consulte el siguiente código:

public class Outer {


    public  class Inner {

    }


    public Inner inner(){
        return new Inner();
    }

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

Si eliminas el comentario en // inner = null; El programa saldrá "¡Estoy destruido!", pero mantener esto comentado no lo hará.
La razón es que todavía se hace referencia a la instancia interna blanca. GC no puede recopilarla y, debido a que hace referencia (tiene un puntero a) la instancia externa, tampoco se recopila.Tener suficientes de estos objetos en su proyecto y puede quedarse sin memoria.
En comparación con las clases internas estáticas que no tienen un punto para la instancia de clase interna porque no está relacionada con la instancia sino con la clase.El programa anterior puede imprimir "¡Estoy destruido!"si haces que la clase interna sea estática y se crea una instancia con Outer.Inner i = new Outer.Inner();

Los términos se usan indistintamente.Si quieres ser realmente pedante al respecto, entonces podría Defina "clase anidada" para referirse a una clase interna estática, una que no tiene una instancia adjunta.En el código, es posible que tengas algo como esto:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Sin embargo, esa no es realmente una definición ampliamente aceptada.

La clase anidada es un término muy general:Cada clase que no es de nivel superior es una clase anidada.Una clase interna es una clase anidada no estática.Joseph Darcy escribió una muy buena explicación sobre Clases anidadas, internas, de miembros y de nivel superior.

Mmm...una clase interna ES una clase anidada...¿Te refieres a clase anónima y clase interna?

Editar:Si realmente te refieres a interno versus anónimo...una clase interna es simplemente una clase definida dentro de una clase como por ejemplo:

public class A {
    public class B {
    }
}

Mientras que una clase anónima es una extensión de una clase definida de forma anónima, no se define ninguna "clase real", como en:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

Edición adicional:

Wikipedia afirma que hay una diferencia en Java, pero llevo 8 años trabajando con Java, y es la primera vez que escucho tal distinción...sin mencionar que no hay referencias allí que respalden el reclamo...En pocas palabras, una clase interna es una clase definida dentro de una clase (estática o no), y anidada es solo otro término que significa lo mismo.

Existe una sutil diferencia entre clases anidadas estáticas y no estáticas...Básicamente, las clases internas no estáticas tienen acceso implícito a los campos de instancia y métodos de la clase adjunta (por lo tanto, no se pueden construir en un contexto estático, será un error del compilador).Las clases anidadas estáticas, por otro lado, no tienen acceso implícito a campos y métodos de instancia, y PUEDEN construirse en un contexto estático.

Dirigido a estudiantes que son principiantes en Java y/o clases anidadas

Las clases anidadas pueden ser:
1.Clases anidadas estáticas.
2.Clases anidadas no estáticas.(también conocido como clases internas) =>Por favor recuerda esto


1.Clases internas
Ejemplo:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


Las clases internas son subconjuntos de clases anidadas:

  • la clase interna es un tipo específico de clase anidada
  • las clases internas son subconjuntos de clases anidadas
  • Puedes decir que un La clase interna también es una clase anidada, pero puedes NO decir que una clase anidada también es una clase interna.

Especialidad de clase interior:

  • instancia de una clase interna tiene acceso a todos de los miembros de la clase externa, incluso aquellos que están marcados como "privados"


2.Clases anidadas estáticas:
Ejemplo:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

Caso 1: crear una instancia de una clase anidada estática a partir de una clase no envolvente

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

Caso 2: crear una instancia de una clase anidada estática a partir de una clase adjunta

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

Especialidad de clases de Estática:

  • La clase interna estática solo tendría acceso a los miembros estáticos de la clase externa y no tendría acceso a los miembros no estáticos.

Conclusión:
Pregunta: ¿Cuál es la principal diferencia entre una clase interna y una clase anidada estática en Java?
Respuesta: simplemente revise los detalles de cada clase mencionada anteriormente.

clase interna y clase estática anidada en Java ambas son clases declaradas dentro de otra clase, conocida como clase de nivel superior en Java.En la terminología de Java, si declara una clase anidada estática, se llamará clase estática anidada en Java, mientras que las clases anidadas no estáticas simplemente se denominan clase interna.

¿Qué es la clase interna en Java?

Cualquier clase que no sea de nivel superior o no esté declarada dentro de otra clase se conoce como clase anidada y, fuera de esas clases anidadas, las clases que se declaran no estáticas se conocen como clase interna en Java.Hay tres tipos de clases internas en Java:

1) Clase interna local: se declara dentro de un bloque de código o método.
2) Clase interna anónima: es una clase que no tiene un nombre al que hacer referencia y se inicializa en el mismo lugar donde se crea.
3) Miembro de clase interna: se declara como miembro no estático de la clase externa.

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in java");
        }
    }
}

¿Qué es la clase estática anidada en Java?

La clase estática anidada es otra clase que se declara dentro de una clase como miembro y se vuelve estática.La clase estática anidada también se declara como miembro de una clase externa y puede hacerse privada, pública o protegida como cualquier otro miembro.Uno de los principales beneficios de la clase estática anidada sobre la clase interna es que la instancia de la clase estática anidada no está adjunta a ninguna instancia adjunta de la clase externa. Tampoco necesita ninguna instancia de clase externa para crear una instancia de clase estática anidada en Java..

1) Puede acceder miembros de datos estáticos de clase exterior incluido privado.
2) La clase anidada estática no puede acceder miembro de datos no estático (instancia) o método.

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in java");
        }
    }
}

Árbitro: Clase interna y clase estática anidada en Java con ejemplo

Creo que la gente aquí debería notar en Poster que:La clase Static Nest es solo la primera clase interna.Por ejemplo:

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

Entonces, en resumen, la clase estática no depende de qué clase contiene.Entonces, no pueden hacerlo en clase normal.(porque la clase normal necesita una instancia).

Cuando declaramos una clase miembro estática dentro de una clase, se la conoce como clase anidada de nivel superior o clase anidada estática.Se puede demostrar de la siguiente manera:

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

Cuando declaramos una clase miembro no estática dentro de una clase, se la conoce como clase interna.La clase interna se puede demostrar de la siguiente manera:

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}

El siguiente es un ejemplo de static nested class y inner class:

Clase exterior.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

Prueba de clase externa:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}

Creo que ninguna de las respuestas anteriores le brinda un ejemplo real de la diferencia entre una clase anidada y una clase anidada estática en términos de diseño de aplicación.Y la principal diferencia entre la clase anidada estática y la clase interna es la capacidad de acceder al campo de instancia de la clase externa.

Echemos un vistazo a los dos ejemplos siguientes.

Clase de nido estático:Un buen ejemplo del uso de clases anidadas estáticas es el patrón de creación (https://dzone.com/articles/design-patterns-the-builder-pattern).

Para BankAccount utilizamos una clase anidada estática, principalmente porque

  1. Se podría crear una instancia de clase nido estática antes que la clase externa.

  2. En el patrón del constructor, el constructor es una clase auxiliar que se utiliza para crear la cuenta bancaria.

  3. BankAccount.Builder solo está asociado con BankAccount.Ninguna otra clase está relacionada con BankAccount.Builder.por lo que es mejor organizarlos juntos sin utilizar convenciones de nombres.
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

Clase interna:Un uso común de las clases internas es definir un controlador de eventos.https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

Para MyClass, usamos la clase interna, principalmente porque:

  1. La clase interna MyAdapter necesita acceder al miembro de la clase externa.

  2. En el ejemplo, MyAdapter solo está asociado con MyClass.Ninguna otra clase está relacionada con MyAdapter.entonces es mejor organizarlos juntos sin usar una convención de nombres

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}

En primer lugar, no existe una clase llamada clase estática. El uso del modificador estático con la clase interna (llamada clase anidada) dice que es un miembro estático de la clase externa, lo que significa que podemos acceder a ella como con otros miembros estáticos y sin tener ningún tipo de clase. instancia de clase externa.(Lo cual es el beneficio de la estática originalmente).

La diferencia entre usar una clase anidada y una clase interna normal es:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Primero podemos crear una instancia de Outerclass y luego podemos acceder a Inner.

Pero si la clase está anidada, la sintaxis es:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

Que utiliza la sintaxis estática como implementación normal de la palabra clave estática.

El lenguaje de programación Java le permite definir una clase dentro de otra clase.Esta clase se denomina clase anidada y se ilustra a continuación:

class OuterClass {
...
class NestedClass {
    ...
    }
}

Las clases anidadas se dividen en dos categorías:estática y no estática.Las clases anidadas que se declaran estáticas se denominan clases anidadas estáticas.Las clases anidadas no estáticas se denominan clases internas.Una cosa que debemos tener en cuenta es que las clases anidadas no estáticas (clases internas) tienen acceso a otros miembros de la clase adjunta, incluso si están declaradas privadas.Las clases anidadas estáticas solo tienen acceso a otros miembros de la clase adjunta si son estáticas.No puede acceder a miembros no estáticos de la clase externa.Al igual que con los métodos y variables de clase, una clase anidada estática está asociada con su clase externa.Por ejemplo, para crear un objeto para la clase anidada estática, utilice esta sintaxis:

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

Para crear una instancia de una clase interna, primero debe crear una instancia de la clase externa.Luego, crea el objeto interno dentro del objeto externo con esta sintaxis:

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

Por qué usamos clases anidadas

  1. Es una forma de agrupar lógicamente clases que sólo se utilizan en un lugar.
  2. Aumenta la encapsulación.
  3. Puede conducir a un código más legible y mantenible.

Fuente: Los tutoriales de Java™: clases anidadas

La diferencia es que se puede crear una instancia de una declaración de clase anidada que también es estática fuera de la clase adjunta.

Cuando tienes una declaración de clase anidada que es no estática, también conocida como clase interna, Java no le permitirá crear una instancia excepto a través de la clase adjunta.El objeto creado a partir de la clase interna está vinculado al objeto creado a partir de la clase externa, por lo que la clase interna puede hacer referencia a los campos de la clase externa.

Pero si es estático, entonces el enlace no existe, no se puede acceder a los campos externos (excepto a través de una referencia ordinaria como cualquier otro objeto) y, por lo tanto, puede crear una instancia de la clase anidada por sí misma.

He ilustrado varios posibles escenarios correctos y de error que pueden ocurrir en el código Java.

    class Outter1 {

        String OutStr;

        Outter1(String str) {
            OutStr = str;
        }

        public void NonStaticMethod(String st)  {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            //  below static attribute not permitted
            // static String tempStatic1 = "static";    

            //  below static with final attribute not permitted         
            // static final String  tempStatic1 = "ashish";  

            // synchronized keyword is not permitted below          
            class localInnerNonStatic1 {            

                synchronized    public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /* 
        //  static method with final not permitted
          public static void innerStaticMethod(String str11) { 

                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }                            

        }

        public static  void StaticMethod(String st)     {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            // static attribute not permitted below
            //static String tempStatic1 = "static";     

            //  static with final attribute not permitted below
            // static final String  tempStatic1 = "ashish";                         

            class localInnerNonStatic1 {
                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /*
    // static method with final not permitted
    public static void innerStaticMethod(String str11) {  
                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }    

        }

        // synchronized keyword is not permitted
        static  class inner1 {          

            static String  temp1 = "ashish";
            String  tempNonStatic = "ashish";
            // class localInner1 {

            public void innerMethod(String str11) {
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            public static void innerStaticMethod(String str11) {
                //  error in below step
                str11 = temp1 +" india";    
                //str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }
            //}
        }

        //synchronized keyword is not permitted below
        class innerNonStatic1 {             

//This is important we have to keep final with static modifier in non
// static innerclass below
            static final String  temp1 = "ashish";  
            String  tempNonStatic = "ashish";
            // class localInner1 {

            synchronized    public void innerMethod(String str11) {
                tempNonStatic = tempNonStatic +" ...";
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            /*
            //  error in below step
            public static void innerStaticMethod(String str11) {   
                            //  error in below step
                            // str11 = tempNonStatic +" india";                     
                            str11 = temp1 +" india";
                            System.out.println("innerMethod ===> "+str11);
                        }*/
                    //}
                }
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top