2009-12-04 13 views
28

¿Cuál es la diferencia entre estas dos declaraciones internas? ¿También comentar sobre ventajas/desventajas?Clase interna en la interfaz vs en la clase

caso A: clase dentro de una clase.

public class Levels { 
    static public class Items { 
    public String value; 
    public String path; 

    public String getValue() { 
     return value;} 
    } 
} 

y caso B: clase dentro de la interfaz.

public interface Levels{ 

    public class Items { 
    public String value; 
    public String path; 

    public String getValue() { 
     return value;} 
    } 
} 

Corrección hecha: a la colocación del método getvalue.

más información: Puedo instanciar la clase Elementos en los dos casos A y B en otra clase que no implementa la interfaz AT ALL.

public class Z{//NOTE: NO INTERFACE IMPLEMENTED here!!!! 
Levels.Items items = new Levels.Items(); 
} 

Desde una interfaz no se instancia, todos los elementos dentro de una interfaz son accesibles en la notación de punto sin interfaz NIVELES instanciado simplemente porque no se puede crear una instancia de una interfaz - hacer efectiva una clase definida dentro de una interfaz permeable a la referencia estática.

Diciendo que la clase Elementos en el caso B no es estática no tiene sentido. Como ambos casos A y B se instancian de la misma manera, no busco la semántica en lo que es estático o interno o anidado. Deja de darme respuestas sobre semántica. Quiero el compilador, el tiempo de ejecución y las diferencias/ventajas de comportamiento, o si ninguno lo dice. No más respuestas sobre semántica por favor !!!!! Un experto en JVM o especificación de VM .NET invitan esta pregunta de respuesta en lugar de libros de texto semanticissiests.

+0

entrevista ¿pregunta? –

+0

No estoy buscando la semántica de si se llama clase interna o anidada. Estoy buscando diferencias de características. –

+2

@ h2g2: después de reformatear el código, el segundo ejemplo es incorrecto, no puede tener un método implementado en una interfaz. O tal vez las llaves no estaban en su lugar correcto ... –

Respuesta

14

Las clases internas estáticas son en su mayoría similares a las clases de nivel superior, excepto que la clase interna tiene acceso a todas las variables estáticas y los métodos de la clase adjunta. El nombre de clase adjunto se agrega efectivamente al espacio de nombre de paquete de la clase interna. Al declarar una clase como una clase interna estática, usted está comunicando que la clase está de alguna manera inseparablemente ligada al contexto de la clase que lo incluye.

Las clases internas no estáticas son menos comunes. La principal diferencia es que las instancias de una clase interna no estática contienen una referencia implícita a una instancia de la clase envolvente y, como resultado, tienen acceso a variables de instancia y métodos de esa instancia de clase adjunta. Esto lleva a algunos modismos de instancias de aspecto raro, por ejemplo: clases internas

Levels levels = new Levels(); // first need an instance of the enclosing class 

// The items object contains an implicit reference to the levels object 
Levels.Items items = levels.new Items(); 

no estáticos son mucho más íntimamente ligadas a sus clases de cerramiento que las clases internas estáticas. Tienen usos válidos (por ejemplo, los iteradores a menudo se implementan como clases internas no estáticas dentro de la clase de la estructura de datos sobre la que iteran).

Es un error común declarar una clase interna no estática cuando realmente solo necesita el comportamiento de la clase interna estática.

+1

clases internas no estáticas son bastante comunes, especialmente en el código de gráficos – gerardw

27

Una clase interna static es una clase anidada, y la no estática se denomina clase interna. Para más información, look here.

Sin embargo, me gustaría citar un fragmento del mismo enlace.

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 de comportamiento una clase de nivel superior que ha sido anidada en otra clase de nivel superior para la conveniencia del paquete .

No usaste la palabra static en el segundo caso. Y cree que sería implícitamente static porque es una interfaz. Tienes razón al asumir eso.

Puede crear instancias de la clase interna en su interfaz, al igual que una clase anidada estática, porque es realmente una clase anidada static.

Levels.Items hello = new Levels.Items(); 

Por lo tanto, la afirmación anterior será válido en ambos casos sus. Su primer caso es de clase anidada estática, y en el segundo caso no especificó static, pero incluso así sería una clase anidada estática porque está en la interfaz. Por lo tanto, no hay diferencia más que el hecho de que uno está anidado en una clase, y el otro en una interfaz.

Normalmente una clase interna en una clase, que no está en la interfaz, se instanciaría como a continuación.

Levels levels = new Levels(); 
Levels.Items items = levels.new Items(); 

otra parte, una clase interna "no estático" tendrá una referencia implícita a su clase externa. Este no es el caso con la clase anidada "estática".

+0

Wlements en una interfaz son estáticos así que el segundo caso es también una clase estática. Tenga en cuenta que la pregunta es que una está envuelta por una clase mientras que la otra está envuelta por una interfaz. La pregunta es: ¿cuáles son las diferencias de comportamiento entre la incrustación de una clase estática en una clase vs en una interfaz. –

+0

Ver mi apéndice. –

0

IMHO, ventaja es que tiene menos clases que abarrotan la carpeta de su proyecto si son triviales; la desventaja es que cuando su clase interna crece con el cambio de requisitos, el maintencien se convierte en su pesadilla.

0

Pensé que el primero declararía una clase Niveles y una clase interna estática llamada Elementos. Los elementos pueden ser referenciados por Levels.Items y serían estáticos.

Mientras que el segundo sería declarar una clase interna sencilla, que se puede acceder mediante el uso de Levels.Items, como en el siguiente:

Levels.Items hello = new Levels.Items(); 

EDIT: esto es totalmente erróneo, lee los comentarios y otras respuestas.

+1

Su primer párrafo es un error total. No se confunda con la palabra 'estático' en este caso. –

+1

Además, su fragmento de código es completamente válido para la clase anidada 'estática '. Pero no para la clase interna. Por lo tanto, su código se vuelve inválido en el contexto en el que lo inserta. Debería ser algo así como 'Levels.Items items = levelsInstance.new Items();'. Tenga en cuenta que no puede crear instancias de una clase interna sin instanciar el exterior. Espero que esto aclare la duda. –

+0

Gracias por corregirme. – BlueTrin

7

Los ejemplos que da de clases anidadas/internas son malos ejemplos (IMO). Además, el segundo ejemplo no es válido para Java, ya que una interfaz solo puede declarar (implícitamente) métodos abstractos. Aquí hay un ejemplo mejor:

public interface Worker { 

    public class Response { 
     private final Status status; 
     private final String message; 
     public Response(Status status, String message) { 
      this.status = status; this.message = message; 
     } 
     public Status getStatus() { return status; } 
     public String getMessage() { return message; } 
    } 

    ... 

    public Response doSomeOperation(...); 
} 

Mediante la integración de la clase de respuesta, estamos indicando que es una parte fundamental de la API trabajador sin otros usos.

La clase Map.Entry es un ejemplo bien conocido de este idioma.

+1

['Map.Entry'] (https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html) es una interfaz. –

15

Si se declara una clase anidada en una interfaz que es siempre pública y estática.Por lo tanto:

public interface Levels{ 
    class Items { 
     public String value; 
     public String path; 

     public String getValue() {return value;} 
    } 
} 

es exactamente el mismo que

public interface Levels{ 
    public static class Items { 
     public String value; 
     public String path; 

     public String getValue() {return value;} 
    } 
} 

E incluso

public interface Levels{ 
    static class Items { 
     public String value; 
     public String path; 

     public String getValue() {return value;} 
    } 
} 

He comprobado esto con -verbose javap y todos ellos producen

Compiled from "Levels.java" 
public class Levels$Items extends java.lang.Object 
    SourceFile: "Levels.java" 
    InnerClass: 
    publiC#14= #3 of #23; //Items=class Levels$Items of class Levels 
    minor version: 0 
    major version: 50 
    Constant pool: 
const #1 = Method #4.#21; // java/lang/Object."<init>":()V 
const #2 = Field #3.#22; // Levels$Items.value:Ljava/lang/String; 
const #3 = class #24; // Levels$Items 
const #4 = class #25; // java/lang/Object 
const #5 = Asciz value; 
const #6 = Asciz Ljava/lang/String;; 
const #7 = Asciz path; 
const #8 = Asciz <init>; 
const #9 = Asciz ()V; 
const #10 = Asciz Code; 
const #11 = Asciz LineNumberTable; 
const #12 = Asciz LocalVariableTable; 
const #13 = Asciz this; 
const #14 = Asciz Items; 
const #15 = Asciz InnerClasses; 
const #16 = Asciz LLevels$Items;; 
const #17 = Asciz getValue; 
const #18 = Asciz ()Ljava/lang/String;; 
const #19 = Asciz SourceFile; 
const #20 = Asciz Levels.java; 
const #21 = NameAndType #8:#9;// "<init>":()V 
const #22 = NameAndType #5:#6;// value:Ljava/lang/String; 
const #23 = class #26; // Levels 
const #24 = Asciz Levels$Items; 
const #25 = Asciz java/lang/Object; 
const #26 = Asciz Levels; 

{ 
public java.lang.String value; 

public java.lang.String path; 

public Levels$Items(); 
    Code: 
    Stack=1, Locals=1, Args_size=1 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: return 
    LineNumberTable: 
    line 2: 0 

    LocalVariableTable: 
    Start Length Slot Name Signature 
    0  5  0 this  LLevels$Items; 


public java.lang.String getValue(); 
    Code: 
    Stack=1, Locals=1, Args_size=1 
    0: aload_0 
    1: getfield #2; //Field value:Ljava/lang/String; 
    4: areturn 
    LineNumberTable: 
    line 7: 0 

    LocalVariableTable: 
    Start Length Slot Name Signature 
    0  5  0 this  LLevels$Items; 


} 
Cuestiones relacionadas