28 Stimmen

Innere Klasse in Schnittstelle vs. in Klasse

Was ist der Unterschied zwischen diesen beiden innerclass-Deklarationen? Welche Vorteile/Nachteile gibt es?

Fall A: Klasse innerhalb einer Klasse.

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

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

und Fall B: Klasse innerhalb der Schnittstelle.

public interface Levels{

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

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

Korrektur: Platzierung der Methode getvalue.

weitere Infos: Ich bin in der Lage, die Klasse Items in beiden Fällen A und B in einer anderen Klasse zu instanziieren, die die Schnittstelle überhaupt nicht implementiert.

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

Da eine Schnittstelle nicht instanziiert wird, sind alle Elemente innerhalb einer Schnittstelle durch die Punktnotation zugänglich, ohne dass LEVELS Schnittstelle instanziiert wird, einfach weil man eine Schnittstelle nicht instanziieren kann - was eine Klasse, die innerhalb einer Schnittstelle definiert ist, für statische Referenzen durchlässig macht.

Die Aussage, dass die Klasse Items im Fall B nicht statisch ist, macht also keinen Sinn. Da beide Fälle A und B auf die gleiche Weise instanziiert werden, bin ich nicht auf der Suche nach der Semantik, was statisch, innerlich oder verschachtelt ist. Hören Sie auf, mir Antworten zur Semantik zu geben. Ich will die Compiler-, Laufzeit- und Verhaltensunterschiede/Vorteile, oder wenn keine, dann sagen Sie es. Keine weiteren Antworten zur Semantik bitte!!!!! Ein Experte für JVM- oder .NET-VM-Spezifikationen sollte bitte diese Frage beantworten und nicht mit Lehrbuchsemantiken.

27voto

Adeel Ansari Punkte 38973

Eine static innere Klasse ist eine verschachtelte Klasse, und die nicht-statische Klasse wird als innere Klasse bezeichnet. Für mehr, siehe hier .

Ich möchte jedoch einen Auszug aus demselben Link zitieren.

Eine statische verschachtelte Klasse interagiert mit den Instanzmitgliedern ihrer äußeren Klasse (und anderen Klassen) genauso wie jede andere Klasse der obersten Ebene. In der Tat, ist eine statische verschachtelte Klasse vom Verhalten her eine Klasse der obersten Ebene, die verschachtelt wurde in eine andere Klasse der obersten Ebene aus Bequemlichkeit verschachtelt wurde.

Du hast das Wort nicht benutzt static im zweiten Fall. Und Sie denken, dass es implizit sein würde static weil es eine Schnittstelle ist. Sie haben Recht, wenn Sie das annehmen.

Sie können die innere Klasse in Ihrer Schnittstelle instanziieren, genau wie eine statische verschachtelte Klasse, da sie in Wirklichkeit eine static verschachtelte Klasse.

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

Die obige Aussage lautet also in Ihren beiden Fällen gültig . In Ihrem ersten Fall handelt es sich um eine statische verschachtelte Klasse, und im zweiten Fall haben Sie nicht angegeben static aber selbst dann wäre es eine statische verschachtelte Klasse, da sie in der Schnittstelle enthalten ist. Es gibt also keinen anderen Unterschied als die Tatsache, dass das eine in einer Klasse und das andere in einer Schnittstelle verschachtelt ist. .

Normalerweise eine innere Klasse in einer Klasse, nicht in der Schnittstelle würde wie folgt instanziiert werden.

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

Außerdem hat eine "nicht-statische" innere Klasse einen impliziten Verweis auf ihre äußere Klasse. Dies ist bei "statischen" verschachtelten Klassen nicht der Fall.

15voto

Henry Punkte 1419

Statische innere Klassen sind den Top-Level-Klassen meist ähnlich, außer dass die innere Klasse Zugriff auf alle スタティック Variablen und Methoden der einschließenden Klasse. Der Name der umschließenden Klasse wird effektiv an den Paketnamensraum der inneren Klasse angehängt. Indem Sie eine Klasse als statische innere Klasse deklarieren, teilen Sie mit, dass die Klasse irgendwie untrennbar mit dem Kontext der umschließenden Klasse verbunden ist.

Nicht-statische innere Klassen sind weniger verbreitet. Der Hauptunterschied besteht darin, dass Instanzen einer nicht-statischen inneren Klasse einen impliziten Verweis auf eine Instanz der umschließenden Klasse enthalten und daher Zugriff auf Instanzvariablen und Methoden dieser umschließenden Klasseninstanz haben. Dies führt zu einigen seltsam anmutenden Instanziierungsidiomen, zum Beispiel:

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(); 

Nicht-statische innere Klassen sind viel enger mit den sie umschließenden Klassen verbunden als statische innere Klassen. Sie haben ihre Berechtigung (zum Beispiel werden Iteratoren oft als nicht-statische innere Klassen innerhalb der Klasse der Datenstruktur, über die sie iterieren, implementiert).

Es ist ein häufiger Fehler, eine nicht-statische innere Klasse zu deklarieren, wenn man eigentlich nur das Verhalten der statischen inneren Klasse benötigt.

15voto

Wenn Sie eine verschachtelte Klasse in einer Schnittstelle deklarieren, ist sie immer öffentlich y スタティック . Also:

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

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

ist genau dasselbe wie

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

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

Und selbst

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

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

Ich habe dies mit javap -verbose überprüft, und sie erzeugen alle

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;

}

7voto

Stephen C Punkte 665668

Die von Ihnen angeführten Beispiele für verschachtelte / innere Klassen sind (IMO) schlechte Beispiele. Außerdem ist das 2. Beispiel kein gültiges Java, da eine Schnittstelle nur (implizit) abstrakte Methoden deklarieren kann. Hier ist ein besseres Beispiel:

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(...);
}

Durch die Einbettung der Klasse Response geben wir an, dass sie ein grundlegender Bestandteil der Worker-API ist und nicht anderweitig verwendet wird.

Die Klasse Map.Entry ist ein bekanntes Beispiel für dieses Idiom.

0voto

Ricky Punkte 32449

IMHO, Vorteil ist, dass Sie weniger Klassen haben, die Ihren Projektordner verstopfen, wenn sie trivial sind; die Nachteil ist, dass, wenn Ihre innere Klasse wächst und sich die Anforderungen ändern, die Instandhaltung zu Ihrem Alptraum werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X