Antworten:
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 ...).
interface
s keine inneren Klassen haben. Sie können den static
Modifikator einer interface
verschachtelten Klasse weglassen, aber es ist dennoch eine verschachtelte Klasse, keine innere Klasse.
B
Klasse 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
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.
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.
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.
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).
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;
}
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);
...
}
Was @Bachi erwähnt, ähnelt den Merkmalen in Scala und wird tatsächlich mithilfe einer verschachtelten Klasse in einer Schnittstelle implementiert. Dies kann in Java simuliert werden. Siehe auch Java-Merkmale oder Mixins-Muster?
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.
Ich habe eine Verwendung für diese Art von Konstrukt gefunden.
Sie haben Zugriff auf alle gruppierten Konstanten. Der Name der Klasse fungiert in diesem Fall als Namespace.
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.