Innere Klasse innerhalb der Schnittstelle


97

Ist es möglich, eine innere Klasse innerhalb einer Schnittstelle zu erstellen ?
Wenn es möglich ist, warum sollten wir eine solche innere Klasse erstellen wollen , da wir keine Schnittstellenobjekte erstellen werden?

Helfen diese inneren Klassen bei jedem Entwicklungsprozess?

Antworten:


51

Ja, Sie können innerhalb einer Java-Schnittstelle sowohl eine verschachtelte als auch eine innere Klasse erstellen (beachten Sie, dass es entgegen der landläufigen Meinung keine " statische innere Klasse " gibt: Dies macht einfach keinen Sinn, es gibt nichts "Inneres" und "Nein". outter "Klasse, wenn eine verschachtelte Klasse statisch ist, also nicht" statisch inner "sein kann).

Wie auch immer, das Folgende kompiliert gut:

public interface A {
    class B {
    }
}

Ich habe gesehen, dass es verwendet wurde, um eine Art "Vertragsprüfer" direkt in die Schnittstellendefinition einzufügen (nun, in der in der Schnittstelle verschachtelten Klasse, die statische Methoden haben kann, im Gegensatz zur Schnittstelle selbst, die dies nicht kann). Sieht so aus, wenn ich mich richtig erinnere.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Beachten Sie, dass ich die Nützlichkeit einer solchen Sache nicht kommentiere, sondern nur Ihre Frage beantworte: Sie kann durchgeführt werden, und dies ist eine Art von Verwendung, die ich gesehen habe.

Jetzt werde ich die Nützlichkeit eines solchen Konstrukts nicht kommentieren und habe gesehen: Ich habe es gesehen, aber es ist kein sehr verbreitetes Konstrukt.

200KLOC-Codebasis hier, wo dies genau null Mal geschieht (aber dann haben wir viele andere Dinge, die wir als schlechte Praktiken betrachten, die genau null Zeit passieren, die andere Leute als völlig normal empfinden würden, also ...).


Können Sie einige Anwendungsbeispiele hinzufügen? Ich habe vor einiger Zeit etwas Ähnliches getestet und nicht verstanden, was ich durch die Verwendung dieser Konstruktion gewinnen kann.
Roman

@Roman: Nun, ich erinnere mich, dass ich dies bei einem Projekt erlebt habe (relativ sauberes Projekt würde ich hinzufügen, aber es waren nicht meine), aber ich weiß nicht, ob es wirklich sauber ist oder nicht. Ich habe ein winziges Beispiel hinzugefügt, das so aussieht, wie ich es gesehen habe, aber noch einmal: Dies war nicht mein Code und ich verwende dieses Konstrukt nicht, daher bin ich nicht am besten qualifiziert, um gültige Beispiele zu finden :) IIRC Die Klasse darin wurde immer benannt, zum Beispiel StateChecker, und Aufrufe sahen immer so aus: A.StateChecker.check (a) oder so ähnlich.
SyntaxT3rr0r

8
Wenn Sie sagen, dass es keine " statische innere Klasse " gibt, ist Ihre Antwort, dass Sie sowohl eine verschachtelte Klasse als auch eine innere Klasse in einer Java-Schnittstelle erstellen können , grundsätzlich falsch. Mit Ihrer eingeschränkten Definition können interfaces keine inneren Klassen haben. Sie können den staticModifikator einer interfaceverschachtelten Klasse weglassen, aber es ist dennoch eine verschachtelte Klasse, keine innere Klasse.
Holger

6
Diese Antwort ist falsch. Schnittstellen können statisch verschachtelte Klassen haben, aber keine inneren Klassen.
Paul Boddington

1
@ PaulBoddington Du hast recht. Selbst wenn 'statisch' entfernt wird, ist die BKlasse eine statisch verschachtelte Klasse und keine innere Klasse. Schnittstellen werden speziell behandelt. Ich konnte dies online nicht erwähnen, außer in der Spezifikation selbst: "Eine Mitgliedsklasse einer Schnittstelle ist implizit statisch und wird daher niemals als innere Klasse betrachtet." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

109

Ja, wir können Klassen in Schnittstellen haben. Ein Anwendungsbeispiel könnte sein

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Hier hat der Code zwei verschachtelte Klassen, die zum Einkapseln von Informationen über Ereignisobjekte dienen, die später in Methodendefinitionen wie getKeyEvents () verwendet werden. Wenn sie sich in der Eingabeschnittstelle befinden, wird der Zusammenhalt verbessert.


3
@Levit Ich frage mich nur, wie die implementierte Klasse aussehen wird.
Überaustausch

1
Würde gerne eine Implementierung in Aktion für die oben genannte Verwendung sehen. Danke dir.
Prakash K

45

Eine gültige Verwendung, IMHO, definiert Objekte, die von den einschließenden Schnittstellenmethoden empfangen oder zurückgegeben werden. Typischerweise Datenhaltestrukturen. Wenn das Objekt nur für diese Schnittstelle verwendet wird, haben Sie die Dinge auf diese Weise zusammenhängender.

Zum Beispiel:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Aber trotzdem ... es ist nur eine Frage des Geschmacks.


34

Zitat aus der Java 7-Spezifikation :

Schnittstellen können Elementtypdeklarationen enthalten (§8.5).

Eine Elementtypdeklaration in einer Schnittstelle ist implizit statisch und öffentlich. Es ist zulässig, einen oder beide dieser Modifikatoren redundant anzugeben.

Es ist NICHT möglich, nicht statische Klassen innerhalb einer Java-Schnittstelle zu deklarieren, was für mich sinnvoll ist.


Danke dir. Dies ist wahrscheinlich die prägnanteste Antwort von allen.
Joseph

1
Dies ist die Antwort, nach der ich gesucht habe. Aber das OP stellt mehrere Fragen. Trotzdem habe ich mein Updoot.
Charlie Wallace

11

Ein interessanter Anwendungsfall besteht darin, eine Art Standardimplementierung für Schnittstellenmethoden über eine innere Klasse bereitzustellen, wie hier beschrieben: https://stackoverflow.com/a/3442218/454667 (um das Problem der Vererbung einzelner Klassen zu überwinden).


Und genau deshalb wären private Mitgliederklassen sinnvoll.
Vincent

7

Es ist sicherlich möglich, und ein Fall, in dem ich es nützlich fand, ist, wenn eine Schnittstelle benutzerdefinierte Ausnahmen auslösen muss. Sie behalten die Ausnahmen mit der zugehörigen Schnittstelle bei, was meiner Meinung nach oft ordentlicher ist, als Ihren Quellbaum mit Haufen trivialer Ausnahmedateien zu verunreinigen.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

Ja, es ist möglich, statische Klassendefinitionen in einer Schnittstelle zu haben, aber der vielleicht nützlichste Aspekt dieser Funktion ist die Verwendung von Aufzählungstypen (bei denen es sich um spezielle statische Klassen handelt). Zum Beispiel können Sie so etwas haben:

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}


1

Wenn Sie komplexere Konstruktionen wie unterschiedliche Implementierungsverhalten wünschen, sollten Sie Folgendes berücksichtigen:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Dies ist Ihre Schnittstelle und dies wird der Implementierer sein:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Kann einige statische Implementierungen bereitstellen, aber das wird nicht verwirrend sein, ich weiß es nicht.


0

Ich habe eine Verwendung für diese Art von Konstrukt gefunden.

  1. Mit diesem Konstrukt können Sie alle statischen Endkonstanten definieren und gruppieren.
  2. Da es sich um eine Schnittstelle handelt, können Sie dies in einer Klasse implementieren.

Sie haben Zugriff auf alle gruppierten Konstanten. Der Name der Klasse fungiert in diesem Fall als Namespace.


0

Sie können auch statische "Helper" -Klassen für allgemeine Funktionen für die Objekte erstellen, die diese Schnittstelle implementieren:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

Ich brauche gerade einen. Ich habe eine Schnittstelle, über die es praktisch wäre, eine eindeutige Klasse aus mehreren Methoden zurückzugeben. Diese Klasse ist nur als Container für Antworten von Methoden dieser Schnittstelle sinnvoll.

Daher wäre es praktisch, eine statische verschachtelte Klassendefinition zu haben, die nur dieser Schnittstelle zugeordnet ist, da diese Schnittstelle der einzige Ort sein sollte, an dem diese Ergebniscontainerklasse jemals erstellt wird.


0

Zum Beispiel Merkmale (smth wie Schnittstelle mit implementierten Methoden) in Groovy. Sie werden zu einer Schnittstelle kompiliert, die eine innere Klasse enthält, in der alle Methoden implementiert sind.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.