In einer Codebasis, an der ich arbeite, bin ich auf folgenden Code gestoßen:
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
...
INSTANCE
wird als deklariert final
. Warum können Objekte hinzugefügt werden INSTANCE
? Sollte dies nicht die Verwendung von final ungültig machen? (Es tut nicht).
Ich gehe davon aus, dass die Antwort etwas mit Zeigern und Gedächtnis zu tun hat, möchte es aber sicher wissen.
Antworten:
final
einfach macht das Objekt Bezug unveränderlich. Das Objekt, auf das es zeigt, ist dadurch nicht unveränderlich.INSTANCE
kann niemals auf ein anderes Objekt verweisen, aber das Objekt, auf das es verweist, kann den Status ändern.quelle
ConfigurationService
Nehmen wir also an, ich deserialisiere ein Objekt und versuche, eine INSTANZ zu machen =deserializedConfigurationService
wäre nicht erlaubt?INSTANCE
, auf ein anderes Objekt zu verweisen. Es spielt keine Rolle, woher das andere Objekt kam. (NB es gibt eineINSTANCE
proClassLoader
, die diese Klasse geladen hat. Sie könnten die Klasse theoretisch mehrmals in eine JVM laden und jede ist separat. Aber dies ist ein anderer technischer Punkt.)Endgültig zu sein ist nicht dasselbe wie unveränderlich zu sein.
final != immutable
Das
final
Schlüsselwort wird verwendet, um sicherzustellen, dass die Referenz nicht geändert wird (dh die Referenz, die sie hat, kann nicht durch eine neue ersetzt werden).Wenn das Attribut jedoch selbst geändert werden kann, ist es in Ordnung, das zu tun, was Sie gerade beschrieben haben.
Zum Beispiel
Wenn wir diese Klasse instanziieren, können wir dem Attribut keinen anderen Wert zuweisen,
someFinalObject
da es endgültig ist .Das ist also nicht möglich:
Aber wenn das Objekt selbst so veränderlich ist:
Dann kann der in diesem veränderlichen Objekt enthaltene Wert geändert werden.
Dies hat den gleichen Effekt wie Ihr Beitrag:
Hier ändern Sie nicht den Wert von INSTANCE, sondern ändern den internen Status (über die Methode providers.add).
Wenn Sie verhindern möchten, dass die Klassendefinition folgendermaßen geändert wird:
Aber es könnte nicht viel Sinn machen :)
Aus dem gleichen Grund müssen Sie übrigens auch den Zugriff darauf synchronisieren .
quelle
Der Schlüssel zum Missverständnis liegt im Titel Ihrer Frage. Es ist nicht das Objekt, das endgültig ist, es ist die Variable . Der Wert der Variablen kann sich nicht ändern, die darin enthaltenen Daten jedoch.
Denken Sie immer daran, dass der Wert dieser Variablen beim Deklarieren einer Referenztypvariablen eine Referenz und kein Objekt ist.
quelle
final bedeutet nur, dass die Referenz nicht geändert werden kann. Sie können INSTANCE nicht einer anderen Referenz zuweisen, wenn diese als endgültig deklariert ist. Der interne Zustand des Objekts ist weiterhin veränderbar.
würde einen Kompilierungsfehler auslösen
quelle
Quelle
Hier ist eine Anleitung , wie Sie ein Objekt unveränderlich machen können .
quelle
Endgültig und unveränderlich sind nicht dasselbe. Final bedeutet, dass die Referenz nicht neu zugewiesen werden kann, sodass Sie nichts sagen können
Unveränderlich bedeutet, dass das Objekt selbst nicht geändert werden kann. Ein Beispiel hierfür ist die
java.lang.String
Klasse. Sie können den Wert einer Zeichenfolge nicht ändern.quelle
In Java ist das Konzept der Unveränderlichkeit nicht in die Sprache integriert. Es gibt keine Möglichkeit, Methoden als Mutator zu markieren. Daher hat die Sprache keine Möglichkeit, die Unveränderlichkeit von Objekten zu erzwingen.
quelle