2010-05-14 15 views
15

Me está costando pasar por las clases anidadas no estáticas en Java. Considere el siguiente ejemplo, que imprime "Interior" y luego "Niño".Java: clases anidadas no estáticas y instance.super()

class Outer { 
    class Inner { 
     Inner() { System.out.println("Inner"); } 
    } 
} 

public class Child extends Outer.Inner { 
    Child(Outer o) { 
     o.super(); 
     System.out.println("Child"); 
    } 
    public static void main(String args[]) { 
     new Child(new Outer()); 
    } 
} 

entiendo que los casos de interior siempre tienen que estar asociados con una instancia exterior, y que eso se aplica a niño demasiado, ya que se extiende Interior. Mi pregunta es qué significa la sintaxis o.super(), ¿por qué llama al constructor interno?

Sólo he visto una llanura super(args) utilizado para llamar al constructor de la superclase y super.method() a llamar a la versión de la superclase de un método reemplazado, pero nunca algo de la forma instance.super().

+0

LOL ... ¿qué tiene esto con la etiqueta 'interview-questions'? – Cristian

+0

Como parte de una entrevista para un puesto de Java, me pidieron que completara un cuestionario de IKM; esta pregunta es una forma simplificada de una en el cuestionario. – Kiv

+0

@Kiv ¿tiene usted un ejemplo del uso de la vida real? – chepseskaf

Respuesta

9

Se denomina "invocación de constructor de clase superificada".

Citando de here:

declaraciones de invocación del constructor explícitos se pueden dividir en dos tipos:

  • invocaciones constructor alternos comienzan con la palabra clave this (posiblemente precedido de argumentos de tipo explícitas). Se usan para invocar a un constructor alternativo de la misma clase.

  • Las invocaciones de constructor de superclase comienzan con la palabra clave super (posiblemente precedida con argumentos de tipo explícito) o una expresión primaria. Se usan para invocar a un constructor de la superclase directa. invocaciones constructor de la superclase pueden subdividirse:

  • Incalificados invocaciones constructor de la superclase comienzan con la palabra clave super (posiblemente precedido de argumentos de tipo explícitas).

  • Las invocaciones de constructor de clase superada comienzan con una expresión primaria. Permiten que un constructor de subclase especifique explícitamente la instancia de cierre inmediato del objeto recién creado con respecto a la superclase directa (§8.1.3). Esto puede ser necesario cuando la superclase es una clase interna.

9

Clases Internas (clases niño no estáticos) son esencialmente clases anidadas (clases hijas estáticos) con enlaces implícitos de vuelta a sus objetos padres. Aquí está el código anterior, escrito en lugar de utilizar una clase anidada estática:

class Outer { 
    static class Inner { 
     final Outer outer; 
     Inner(Outer outer) { 
      this.outer = outer; 
      System.out.println("Inner"); 
     } 
    } 
} 

public class Child extends Outer.Inner { 
    Child(Outer o) { 
     super(o); // o.super(); 
     System.out.println("Child"); 
    } 

    public static void main(String args[]) { 
     new Child(new Outer()); 
    } 
}

En cuanto a esto, usted debe ser capaz de entender lo o.super() estaba haciendo.

+2

De hecho, una clase interna no estática es esencialmente azúcar sintáctica para lo anterior, según entiendo. –

+0

No, una clase estática anidada es esencialmente una clase de nivel externo, que está ahí solo para la conveniencia del empaquetado. –

+1

Bien, a la derecha. Me refiero a que una clase interna * no estática * es azúcar sintáctico en la parte superior del azúcar sintáctico :-D –

2

Conceptualmente, una clase interna no estática "pertenece" a un objeto en particular. Es como si cada uno obtuviera su propia versión de la clase, al igual que un campo o método no estático pertenece a un objeto en particular.

Así que por eso tenemos la sintaxis divertido como instance.new Inner() y instance.super() - para contextos en los que la respuesta a la pregunta “¿pero cuya Inner?” No es inmediatamente evidente. (En un método no estático de la clase externa, sólo se puede decir new Inner(), y como es habitual que es la abreviatura de this.new Inner().)

5

¿Por qué o.super() en Child termina invocando Outer.Inner constructor? Es simple: porque Child extends Outer.Inner, y las llamadas al constructor siempre están encadenadas en la jerarquía.

Aquí hay una ligera expansión de su fragmento para ilustrar:

class Outer { 
    Outer() { 
     System.out.println("Outer"); 
    } 
    void outerMethod() { } 
    class Inner { 
     Inner() { 
      System.out.println("OuterInner"); 
      outerMethod();    
     } 
     String wealth; 
    } 
} 
class OuterChild extends Outer { 
    OuterChild() { 
     System.out.println("OuterChild"); 
    } 
} 
public class OuterInnerChild extends Outer.Inner { 
    OuterInnerChild(Outer o) { 
     o.super(); 
     System.out.println("OuterInnerChild"); 
     this.wealth = "ONE MILLION DOLLAR!!!"; 
    } 
    public static void main(String args[]) { 
     System.out.println(new OuterInnerChild(new Outer()).wealth); 
     new OuterChild(); 
    } 
} 

Esta impresora:

Outer 
OuterInner 
OuterInnerChild 
ONE MILLION DOLLAR!!! 
Outer 
OuterChild 

Algunas observaciones clave:

  • Debido OuterInnerChild extends Outer.Inner, hereda wealth, al igual semántica de subclase normal
    • Y al igual que la semántica de las subclases normales, el constructor de OuterInnerChild cadenas al constructor de Outer.Inner
  • Debido OuterChild extends Outer, sus cadenas de constructor, incluso cuando no se invoca explícitamente
    • Ya sea implícita o explícitamente, la cadenas de constructor de la jerarquía

Pero ¿por qué se invoca la demanda compilador que OuterInnerChild constructor toma un Outer o, y que o.super()?

Ahora que es específico a la semántica clase interna: se hace para asegurar que todas las instancias de OuterInnerChild tiene un encerrando Outer ejemplo para Outer.Inner, la super clase de OuterInnerChild. De lo contrario, el constructor de Outer.Inner no tendría una instancia adjunta de Outer para invocar outerMethod() en.

0

Siempre hay que olvidarse de los principios básicos, en el proceso de llamar a un constructor de subclase, siempre es la primera clase instanciada independientemente de las clases internas/externas. En su escenario, a medida que extiende la clase interna y su clase interna es miembro de la clase padre que necesita ser instanciada, luego llama al constructor de la clase interna real.

Cuestiones relacionadas