Java: Definition von Methoden und Variablen innerhalb der Enum-Konstante

8

Ich habe einige Experimente gemacht und versehentlich einen Code geschrieben, der sehr merkwürdig ist und ich verstehe nicht alles. Ich war sogar überrascht, dass ich es kompilieren kann. Es sieht so aus:

%Vor%

Wie erwartet ist es nicht möglich, auf ein solches Element wie folgt zuzugreifen:

%Vor%

Der Grund ist, dass der Compiler in der Enumeration selbst nach dieser Methode sucht.

Ich vermutete, dass es nicht möglich ist, von außerhalb der Aufzählung auf diese Methoden und Variablen zuzugreifen. Aus diesem Grund habe ich versucht, einen parametrischen Konstruktor zu erstellen und ihn mit einer internen Variable aufzurufen:

%Vor%

Eine solche Konstruktion konnte nicht kompiliert werden. Jetzt habe ich darüber nachgedacht, was es heißt, etwas innerhalb der Konstanten zu definieren, wenn es keine Möglichkeit gibt, darauf zuzugreifen.

Ich habe versucht, die gleichnamigen Methoden sowohl in der Konstante als auch in der Enumeration selbst zu erstellen, um herauszufinden, ob sie irgendwie kollidiert. Hat es nicht!

%Vor%

Und hier kommt der lustige Moment! Ich habe versucht, den Aufruf von myMethod () in der Enumeration fortzusetzen und habe herausgefunden, wie diese Java-Magie funktioniert. Methoden, die innerhalb der Konstante definiert sind, überschreiben Methoden, die in der Enumeration definiert sind.

%Vor%

Allerdings können wir Variable nicht überschreiben, oder? Also war ich neugierig, wie es nur mit Variablen funktioniert.

%Vor%

Jetzt komme ich endlich zu meinen Fragen:

  1. Warum bekomme ich keinen Fehler, wenn ich public method innerhalb der konstanten und linken Enumeration leer ohne diese Methode erstelle? In diesem Fall kann die Methode, die ich gerade definiert habe, nicht heißen. Oder irre ich mich?

    Update: Ich weiß, dass die Enumeration Schnittstelle implementieren kann. Wenn ich es nicht getan habe speziell gesagt, dass der ganze Code sinnlos ist.

    Jemand wies darauf hin, dass selbst dann, wenn auf die Methode nicht von der normalen Sprache aus zugegriffen werden kann So ist es immer noch möglich, Reflektionen zu verwenden. Nun ... Warum entwerfen wir nicht ein unzugänglich ? Stichwort?

    %Vor%

    Eine solche Methode wird in die * .class-Datei kompiliert. Wenn du es benutzen willst, musst du Laden Sie den Bytecode selbst und interpretieren Sie ihn.

    Ich kann einfach nicht verstehen, warum es möglich ist, eine unerreichbare Methode zu definieren. Der einzige Grund Ich kann denken, dass Programmierer arbeitet und noch keine Definition der Schnittstelle hat. Damit Er bereitet gerade den Code für einzelne Methoden vor und fügt später das Schlüsselwort "implementiert" hinzu. Neben das ist unlogisch, es würde immer noch nötig sein, eine solche Methode in allen Konstanten zu haben.

    Ich denke, das sollte mit einem Fehler enden und nicht nur vor unbenutzten Methoden warnen. Du wirst es vielleicht vergessen hinzufügen "implementieren" -Klausel oder Methode in der Aufzählung definieren (was wäre überschrieben) und wird dies sofort nach der ersten Verwendung erkennen. Java ist eine sehr strenge Sprache, also würde ich dieses Verhalten erwarten.

  2. Warum bekomme ich keinen Fehler, wenn ich public variable (oder genauer gesagt Feld) innerhalb der Konstante erstelle? Es kann auf keinen Fall (von außen) zugegriffen werden. Daher macht der Modifikator "public" hier keinen Sinn.

    Update: Es ist mehr oder weniger dasselbe wie im vorherigen Punkt, außer der Sichtbarkeit Modifikator ist hier völlig nutzlos. Es ist wirklich egal, ob es öffentlich ist, geschützt oder privat, weil Sie sowieso nicht darauf zugreifen können. Ich denke, das ist ein Fehler.

  3. Warum ist es möglich eine Klasse zu definieren (ohne Sichtbarkeitsmodifikatoren), aber nicht interface ? Ja, du würdest wahrscheinlich keine so brutale Aufzählung schreiben wollen, dass du Klassen innerhalb der Konstanten definieren und sogar dort Vererbung verwenden musst. Aber wenn es möglich ist, Klassen und abstrakte Klassen zu definieren, erscheint es etwas seltsam.

    Update: Dies ist definitiv nicht etwas, was Sie regelmäßig brauchen, aber ich verstehe dass es nützlich sein könnte. Aber warum ist es nur auf Klassen beschränkt und Schnittstellen können nicht sein auch definiert?

    %Vor%
  4. Hast du irgendwo eine solche Funktionalität benutzt? Ich kann mir vorstellen, dass es nützlich sein könnte, aber es ist wenig verwirrend. Als ich nach Ressourcen suchte, fand ich nichts.

    Update: Ich würde gerne ein praktisches Beispiel mit überschriebenen Methoden in einem Enum-Konstantenklassen-Body sehen. Hast du es in einem Open-Source-Projekt gesehen?

Umgebung:

%Vor%

Danke für Ihre Zeit und für Ihre Antworten!

    
tzima 23.08.2013, 00:32
quelle

4 Antworten

2
  

Warum bekomme ich keinen Fehler, wenn ich öffentliche Methode innerhalb der konstanten und linken Enumeration leer ohne diese Methode erstellen? In diesem Fall kann die Methode, die ich gerade definiert habe, überhaupt nicht aufgerufen werden. Oder irre ich mich?

Tatsächlich sollte der Compiler sehen können, dass die Methode außerhalb des Klassenkörpers der Enum-Konstanten nicht sichtbar ist und Sie warnen, wenn sie nicht verwendet wird - ich weiß sicher, dass Eclipse dies tut. Wie dasblinkenlight darauf hinweist , kann eine solche öffentliche Methode tatsächlich eine Überschreibung einer Methode sein, die von einer Schnittstelle deklariert wird, die die Enumeration implementiert .

  

Ich kann einfach nicht verstehen, warum es möglich ist, eine unerreichbare Methode zu definieren. Der einzige Grund, warum ich denken kann, ist, dass der Programmierer arbeitet und noch keine Definition der Schnittstelle hat. Er bereitet gerade den Code für einzelne Methoden vor und fügt später das Schlüsselwort "implementiert" hinzu. Abgesehen davon ist es unlogisch, dass es immer noch eine solche Methode in allen Konstanten geben muss.

Wie ich bereits angemerkt habe, gilt dies nicht speziell für konstante Enum-Klassen. Es gibt viele Bereiche - private verschachtelte Klassen, lokale Klassen, anonyme Klassen -, bei denen es für ein Mitglied sinnlos ist, öffentlich zu sein.

Das Problem mit dieser Frage ist, dass nur die Sprachdesigner es wirklich beantworten können. Ich kann nur meine Meinung sagen, nämlich: Warum sollte es ein Fehler sein? Die Sprachspezifikation ist nicht kostenlos - alles in der JLS muss sorgfältig definiert und implementiert und getestet werden. Die wirkliche Frage ist, welchen Nutzen hat es, es zu einem Fehler zu machen? Die bloße Tatsache ist, dass, während ein ungenutztes Mitglied einen Fehler anzeigt (daher die Warnung), es nichts tut .

  

Warum bekomme ich keinen Fehler, wenn ich eine öffentliche Variable (oder ein Feld, um genau zu sein) innerhalb der Konstante erstelle? Es kann auf keinen Fall (von außen) zugegriffen werden. Daher macht der Modifikator "public" hier keinen Sinn.

Wie oben - der Compiler oder zumindest einige IDEs warnen Sie, wenn eine Variable nicht verwendet wird. Dies ist dasselbe, als ob Sie eine public Variable in einer private geschachtelten Klasse deklariert hätten und diese dann nirgends referenziert hätten. In jedem Fall ist es nicht die Priorität der JLS, solche Situationen zu verbieten, obwohl das Auge der Reflexion alles sieht.

  

Es ist weniger dasselbe wie im vorherigen Punkt, außer dass der Sichtbarkeitsmodifikator hier völlig unbrauchbar ist. Es spielt keine Rolle, ob es öffentlich, geschützt oder privat ist, weil Sie sowieso nicht darauf zugreifen können. Ich denke, das ist ein Fehler.

Hier vergesst du, dass Mitglieder immer noch innerhalb des Körpers der Enum-Konstantenklasse verwendet werden können - denke zum Beispiel an eine Hilfsmethode. Es ist nur so, dass in diesem Fall Zugriffsmodifikatoren einfach keine Rolle spielen und weggelassen werden können.

  

Warum ist es möglich, eine Klasse (ohne Sichtbarkeitsmodifikatoren) zu definieren, aber keine Schnittstelle? Ja, du würdest wahrscheinlich keine so brutale Aufzählung schreiben wollen, dass du Klassen innerhalb der Konstanten definieren und sogar dort Vererbung verwenden musst. Aber wenn es möglich ist, Klassen und abstrakte Klassen zu definieren, erscheint es etwas seltsam.

Das ist eine gute Frage, und ich brauchte eine Weile, um zu verstehen, was Sie meinen. Um das klarzustellen, sagst du, dass in dieser Situation nur die Klasse erlaubt ist:

%Vor%

Um das herauszufinden, versuchen Sie, die Klasse static :

zu erstellen %Vor%

Jetzt sind beide nicht erlaubt. Warum? Nothing static kann in einem Enum-Konstanten-Body deklariert werden, da sich der Body im Kontext der -Instanz dieser Konstante befindet. Dies ist vergleichbar mit dem Bereich einer inneren (nicht-statischen geschachtelten) Klasse:

%Vor%

Statische Variablen, Methoden, Klassen und Schnittstellen (die implizit statisch sind, wenn sie verschachtelt sind) sind in einem solchen Bereich verboten.

  

Hast du irgendwo eine solche Funktionalität benutzt? Ich kann mir vorstellen, dass es nützlich sein könnte, aber es ist wenig verwirrend. Als ich nach Ressourcen suchte, fand ich nichts.

Es ist unklar, auf welche Funktionen Sie hier speziell Bezug nehmen. Bitte aktualisieren Sie die Frage, um anzugeben, nach was genau Sie suchen - überschriebene Methoden in einem Enum-Konstantenklassen-Body? Felder? Helfer-Methoden? Helfer Klassen? Bitte klären.

    
Paul Bellora 23.08.2013, 01:13
quelle
4

OK, ich habe diese Funktionalität tatsächlich benutzt! Ich schreibe einfaches Spiel und möchte zwei Soundpacks bereitstellen. Da das Spiel sehr einfach ist und wahrscheinlich nicht in der Zukunft erweitert werden wird, wollte ich keinen komplizierten Mechanismus schaffen, um so etwas zu erreichen.

%Vor%

Also, ich habe gerade das Enum definiert, das Sie oben sehen. In der Klasse, die die gesamte Konfiguration enthält, ist nur ein Attribut wie folgt:

%Vor%

Wenn ich jetzt etwas Sound spielen muss, kann ich den Pfad sehr einfach finden:

%Vor%

Die Konfiguration kann sehr einfach geändert werden, indem einfach ein anderer Wert dem Feld soundPack zugewiesen wird. Wenn der Sound noch nicht geladen ist (und es besteht die Möglichkeit, dass sie nicht verwendet werden, weil ich viel Lazy Loading verwende), werden die Änderungen sofort wirksam. Ohne etwas anderes zu ändern.

Wenn ich ein neues Soundpaket hinzufügen möchte, würde dies auch durch Definition einer neuen Konstante in dieser Enumeration geschehen. Eclipse zeigt eine Warnung an, ich drücke einfach STRG + 1 und erzeuge diese Methoden. Es ist also auch sehr einfach.

Ich weiß, dass dies nicht der beste Weg ist, dies zu tun. Aber es ist einfach, es ist schnell und was ist das Wichtigste: Ich wollte versuchen das in der Praxis zu verwenden. : -)

    
tzima 23.08.2013 18:37
quelle
3
  

[...] die Methode, die ich gerade definiert habe, kann überhaupt nicht aufgerufen werden. Oder irre ich mich?

Richtig, Sie irren sich: Java enum s kann Schnittstellen wie folgt implementieren:

%Vor%

Sie haben nun Zugriff auf myMethod in VALUE_1 . Natürlich wären Sie gezwungen, diese Methode in anderen Werten oder in enum selbst zu implementieren. Außerdem könnten Sie jederzeit auf solche Methoden zugreifen, die durch die Sprache nicht zugänglich sind, durch Reflektion.

Was die öffentlichen Variablen betrifft, so scheint es, als wäre hier nur eine Reflexion möglich. Dennoch gibt es keinen Grund, dies zu verbieten (obwohl es schwer ist, sich eine nützliche Anwendung für sie vorzustellen).

  

Haben Sie eine solche Funktion irgendwo benutzt?

Ich habe eine enum verwendet, die eine Schnittstelle implementiert hat, wobei jede Konstante die Methoden der Schnittstelle auf ihre spezifische Weise implementiert.

    
dasblinkenlight 23.08.2013 00:46
quelle
2

Aus der JLS

  

Der optionale Klassenkörper einer Enum-Konstante definiert implizit ein   anonyme Klassendeklaration (§15.9.5), die sofort erweitert   Einschließender Enum-Typ.

Erstellen Sie so etwas

%Vor%

Wenn in der Enum selbst (oder ihren Supertypen) kein myMethod() deklariert ist, wird eine Methode auf die abstrakte Klasse beschränkt, d. kann nicht außerhalb dieses Körpers aufgerufen werden. Ähnliches Verhalten gilt für ein Feld, das innerhalb dieses Körpers deklariert ist. Der public -Kennzeichner ändert nichts.

Bearbeiten

Bei der dritten Frage, weil Sie eine anonyme Klasse deklarieren, hat keine andere Komponente Zugriff auf die Schnittstelle (um sie zu implementieren). Eine Klasse hingegen bietet Verhalten und kann daher innerhalb der anonymen Klasse verwendet werden.

Sehen Sie sich einige Einschränkungen für anonyme Klassen an.

Bearbeiten beenden

Wie für 4. Ich habe noch nie einen solchen Code in der Praxis gesehen. Es kann nützlich sein, wenn Sie möchten, dass eine Hilfsmethode ein bestimmtes Verhalten ausführt, das nur für diese spezifische Enumeration relevant ist. Das wäre sehr seltsam und wäre wahrscheinlich besser für eine richtige Klasse geeignet.

Sehen Sie sich die Singleton-Muster mit einem Enum implementiert . Vielleicht möchten Sie viele Singletons mit jeder eigenen Implementierung haben. Eine anonyme Enum-Klassen-Deklaration mit überschriebenen Methoden könnte ein Weg sein, dies zu erreichen.

    
Sotirios Delimanolis 23.08.2013 00:42
quelle