Stellen Sie sich vor, ich habe diese Klasse:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Jetzt habe ich eine andere Klasse, die die obige Klasse verwendet:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
Das ist also das Problem: Ich habe von außen auf ein privates Feld einer Klasse zugegriffen! Wie kann ich das verhindern? Ich meine, wie kann ich dieses Array unveränderlich machen? Bedeutet dies, dass Sie sich mit jeder Getter-Methode nach oben arbeiten können, um auf das private Feld zuzugreifen? (Ich möchte keine Bibliotheken wie Guava. Ich muss nur den richtigen Weg kennen, um dies zu tun.)
final
funktioniert die Änderung des Feldes verhindern . Das Verhindern der Modifikation desObject
durch ein Feld genannten ist jedoch komplizierter.Antworten:
Sie müssen eine Kopie Ihres Arrays zurückgeben.
quelle
Unmodifiable List
.Wenn Sie eine Liste anstelle eines Arrays verwenden können, bietet Collections eine nicht änderbare Liste :
quelle
Collections.unmodifiableList(list)
als Zuordnung zum Feld verwendet wird, um sicherzustellen, dass die Liste nicht von der Klasse selbst geändert wird.String
sind, aber wenn sie veränderbar sind, muss möglicherweise etwas getan werden, um zu verhindern, dass der Aufrufer sie ändert.Der Modifikator
private
schützt nur das Feld selbst vor dem Zugriff durch andere Klassen, nicht jedoch die Objektreferenzen in diesem Feld. Wenn Sie ein referenziertes Objekt schützen müssen, geben Sie es einfach nicht weiter. Veränderungzu:
oder zu
quelle
Das
Collections.unmodifiableList
wurde schon erwähnt - dasArrays.asList()
seltsamerweise nicht! Meine Lösung wäre auch, die Liste von außen zu verwenden und das Array wie folgt zu verpacken:Das Problem beim Kopieren des Arrays ist: Wenn Sie dies jedes Mal tun, wenn Sie auf den Code zugreifen und das Array groß ist, werden Sie mit Sicherheit viel Arbeit für den Garbage Collector erstellen. Die Kopie ist also ein einfacher, aber wirklich schlechter Ansatz - ich würde sagen "billig", aber speicherintensiv! Besonders wenn Sie mehr als nur 2 Elemente haben.
Wenn Sie sich den Quellcode von ansehen
Arrays.asList
undCollections.unmodifiableList
dort tatsächlich nicht viel erstellt wird. Der erste umschließt das Array nur, ohne es zu kopieren, der zweite umschließt nur die Liste und macht Änderungen daran nicht verfügbar.quelle
immutableList
ganzen Weg!Arrays.asList
undCollections.unmodifiableList
für größere Arrays wahrscheinlich billiger sind. Vielleicht kann jemand berechnen, wie viele Elemente erforderlich sind, aber ich habe bereits Code in for-Schleifen mit Arrays gesehen, die Tausende von Elementen enthalten, die kopiert werden, um Änderungen zu verhindern - das ist verrückt!Sie können auch verwenden,
ImmutableList
was besser als der Standard sein sollteunmodifiableList
. Die Klasse ist Teil von Guava- Bibliotheken, die von Google erstellt wurden.Hier ist die Beschreibung:
Hier ist ein einfaches Beispiel für die Verwendung:
quelle
Test
Klasse nicht vertrauen können , dass die zurückgegebene Liste unverändert bleibt . Sie müssen sicherstellen, dass diesImmutableList
zurückgegeben wird und dass die Elemente der Liste ebenfalls unveränderlich sind. Ansonsten sollte meine Lösung auch sicher sein.Unter diesem Gesichtspunkt sollten Sie die Systemarray-Kopie verwenden:
quelle
clone
und nicht so präzise ist.Sie können eine Kopie der Daten zurückgeben. Der Anrufer, der die Daten ändern möchte, ändert nur die Kopie
quelle
Der Kern des Problems besteht darin, dass Sie einen Zeiger auf ein veränderliches Objekt zurückgeben. Hoppla. Entweder machen Sie das Objekt unveränderlich (die nicht modifizierbare Listenlösung) oder Sie geben eine Kopie des Objekts zurück.
Im Allgemeinen schützt die Endgültigkeit von Objekten Objekte nicht vor Änderungen, wenn sie veränderlich sind. Diese beiden Probleme sind "Cousins küssen".
quelle
Es ist eine gute Idee, eine nicht veränderbare Liste zurückzugeben. Eine Liste, die während des Aufrufs der Getter-Methode nicht geändert werden kann, kann jedoch weiterhin von der Klasse oder von Klassen, die von der Klasse abgeleitet sind, geändert werden.
Stattdessen sollten Sie jedem, der die Klasse erweitert, klar machen, dass die Liste nicht geändert werden sollte.
In Ihrem Beispiel könnte dies zu folgendem Code führen:
Im obigen Beispiel habe ich das
STRINGS
Feld öffentlich gemacht. Im Prinzip können Sie den Methodenaufruf abschaffen, da die Werte bereits bekannt sind.Sie können die Zeichenfolgen auch einem
private final List<String>
Feld zuweisen, das während der Erstellung der Klasseninstanz nicht geändert werden kann. Die Verwendung einer Konstante oder von Instanziierungsargumenten (des Konstruktors) hängt vom Design der Klasse ab.quelle
Ja, Sie sollten eine Kopie des Arrays zurückgeben:
quelle