2014-12-26 7 views
11

in Java ist es Konvention (soweit es mich betrifft), um Ihre Feldvariablen privat zu halten und mit Getter und/oder Setter auf sie zuzugreifen. Auf diese Weise können Sie Regeln zum Ändern der Werte der Variablen festlegen.Sind Getter erforderlich, wenn das Feld vars endgültig ist?

Aber was ist, wenn die Variablen endgültig sind? Beispiel:

public class Test { 

    public final int MY_INT; 

    public Test(int myInt) { 
     MY_INT = myInt; 
    } 

} 

Wäre das erlaubt? Es ist kompiliert und funktioniert gut, aber wird es als guter Code betrachtet?

+4

Sie haben keine Getter/Setter in Ihnen Code, nur Konstruktor, so dass Sie im Grunde erstellen unveränderlichen Objekt, das ist gut –

+2

@pbabcdefp es ist endgültig –

+0

Sorry. Temporäres Gehirnfrost. –

Antwort

16

Dies kompiliert, aber es gilt nicht als guter Code.

MY_INT verletzt die Namenskonvention: Namen mit allen Kappen für static final Variablen verwendet werden, auch als „Klassenkonstanten“ bekannt (siehe this und this, Google's Java style guide auch). Um den Namenskonventionen zu entsprechen, wäre es besser, in myInt umzubenennen.

Es wird empfohlen, einen Getter bereitzustellen, um Implementierungsdetails Ihrer Klasse auszublenden. Schnittstellen enthalten nur Methoden, keine Felder. Wenn Sie zulassen, dass andere Klassen auf dieses Feld mit dem Namen verweisen, verlieren Sie später die Freiheit, den Namen oder Ihre interne Darstellung zu ändern.

Aber am wichtigsten, Unterklassen können Felder nicht überschreiben, sie können Methoden nur überschreiben. Wenn Sie anstelle eines Felds einen Getter angeben, können die Unterklassen dies überschreiben und ein anderes Verhalten implementieren. So wäre es besser, einen Getter bereitzustellen und direkten Zugriff auf das Feld selbst zu verbieten.

(Dank @Sotirios Delimanolis für die Codierung Styleguide Links, sehr geschätzt!)

+0

Bist du sicher? Ich habe immer gedacht, dass alle Konstanten Großbuchstaben sein sollten. – Ludwig

+3

Ich denke, die am besten geeignete Antwort auf, ob dies aktiviert werden sollte oder nicht, wird auf einer anderen SE-Website erläutert: http://programmers.stackexchange.com/questions/252243/naming-convention-final-fields-not-static – nmagerko

+1

@ Ludwig ja absolut. Die [relevant] (http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-135099.html#367) [docs] (http://docs.oracle.com/javase/tutorial/java /nutsandbolts/variables.html) sind nicht gerade einfach zu lesen, aber die All Caps Konvention ist nur für 'statische final' Variablen (" Klassenkonstanten "), nicht für" final ". In dem Post, der von @nmagerko verlinkt wird, macht @MichaelT einen ausgezeichneten Punkt über die Serialisierungslogik. – janos

4

Wenn der Client auf das öffentliche Feld in Ihrer Frage zugreifen könnte, bevor ihm ein Wert zugewiesen wurde (d. H. Ohne den Konstruktor aufzurufen), liegt ein offensichtliches Problem vor. Insbesondere konnte dieses Feld keinen erwarteten/richtigen Wert haben, wenn ein Client versuchte, darauf zuzugreifen. Wie jedoch in den Kommentaren ausgeführt wurde, haben Sie Test.MY_INT nicht mit einem static Bezeichner deklariert, so dass es im Wesentlichen unmöglich ist, den Wert dieser Konstante abzurufen, ohne zuerst den Konstruktor aufzurufen.

Daher erscheint es (in Bezug auf die Unveränderlichkeit) sinnvoll zu tun, was Sie tun. In Bezug auf "guten Code" sind Sie jedoch (wie andere gesagt haben) gezwungen, sich selbst und Ihre Kunden ausdrücklich auf diesen Wert namentlich zu beziehen. Wenn Sie jedoch einen Getter verwenden und den Namen MY_INT ändern müssen, während Sie den Zweck der Konstanten beibehalten, sind weder Sie noch Ihr Client gezwungen, etwas zu ändern, das über die Implementierung in Test hinausgeht.

Um genauer zu sein, stelle ich Ihre Klasse mit einem Getter und privatisierten Konstante.

public class Test { 

    private final int MY_INT; 

    public Test(int myInt) { 
     MY_INT = myInt; 
    } 

    public int getAssignedIntValue() { 
     return MY_INT; 
    } 

} 

ich die zugewiesene ganzzahligen Wert wie so erhalten würde:

Test test = new Test(1); 
// with your class 
test.MY_INT; 
// with the above class  
test.getAssignedIntValue(); 

Nun, sage ich MY_INT-myInt anzupassen Namenskonventionen umbenennen. In beiden Fällen muss ich alle Vorkommen von MY_INT in der Test Klasse ändern. Aber der Unterschied zwischen den beiden Implementierungen wird deutlich, wenn ich den Wert mit dem neuen konstanten Namen bekommen muß:

// if this is the old code from above 
Test test = new Test(1); 
// I need to change this to test.myInt, or I get an ERROR! 
test.MY_INT; 
// since I didn't change the name of the getter, all is well 
test.getAssignedIntValue(); 

Hinweis: Dies ist zwar eine akzeptable Antwort gewesen sein mag, ist es nicht unbedingt die am besten zutreffende Argumentation . Bitte beachten Sie this answer für Überlegungen in einem allgemeineren Kontext gegeben.

+3

Sie würden ziemlich schnell beim Zugriff ohne eine Instanz fehlschlagen. –

+0

'Test.MY_INT' ist immer noch gültig, trotz was danach kommt, nicht wahr? Bitte erläutern Sie, wenn Sie eine Chance haben – nmagerko

+2

Nein. Es würde nicht einmal in einem IDE-Autosuggest auftauchen. –

3

Ja, Sie können. Solange Sie diese Variable nicht auf Klassenebene oder von anderen Sätzen initialisieren.

+1

Ich denke nicht, dass dies eine gute Antwort aus ähnlichen Gründen ist. –

3

Ich persönlich mag öffentliche Felder nicht, es sei denn, Ihre Klasse ist nur eine Datenklasse. Deine Klasse ist unveränderlich, aber bist du dir sicher, dass du sie niemals veränderbar machen willst? Wenn eines Tages aus irgendeinem Grund eine veränderbare Kopie benötigt wird, ist es einfacher, sowohl veränderbare als auch unveränderliche Kopien mit Gettern und Setter zu haben.

Wenn Sie öffentliche Felder haben, verwenden Kunden Ihre Felder in ihrem Code und Sie können ihre Namen in Zukunft nicht mehr ändern.

Sie brechen die Kapselung auf diese Weise.

4

Die Anbieter Antworten unvollständig sind (auch die, als „die Antwort“ ausgewählt). Überlegen Sie, was passieren würde, wenn das fragliche Feld eine Sammlung oder ein Array von Objekten wäre. Es ist eine gute Vorgehensweise, ALLE Felder privat zu machen und "Getter" für diese Felder bereitzustellen. Genauer gesagt sollte dein Getter eine (unveränderliche) Referenz auf das Feld (d. H. String) ODER eine defensive Kopie von veränderbaren Feldern (d. H. Ein Array von Objekten) zurückgeben. Dies liegt daran, dass Sie, selbst wenn Sie die Basisadresse des fraglichen Objekts nicht ändern können, die Interna des Objekts (Array oder Sammlung) ändern können, indem Sie einfach die Basisadresse abrufen. Beachten Sie, dass ich bei veränderlichen Feldern nicht nur Arrays oder Sammlungen betrachte. Es gilt für jede veränderbare Klasse.

Gehen wir zurück auf die Frage, sind Getter ERFORDERLICH? Die Antwort ist nein. JEDOCH, wenn Sie robusten Code haben möchten, ist es in Ihrem besten Interesse, diese Best Practices zu befolgen; auch wenn es nur um gute Gewohnheiten zu schaffen ist. Wenn Sie sie nicht regelmäßig üben, werden Sie beim Codieren keine guten Praktiken befolgen (und höchstwahrscheinlich auch andere in Ihrem Projekt nicht).