Wie andere sagten, es sei denn, es ist ein primitiver Typ, erhalten Sie einen Verweis auf das Objekt. Es ist ähnlich wie ein Zeiger in C++, es ermöglicht Ihnen den Zugriff auf das Objekt, aber im Gegensatz zu C++ - Verweis (Zeiger auf die Speicheradresse einer Variablen) können Sie es nicht durch ein anderes Objekt ersetzen. Nur Setter kann das tun.
Ich sehe zwei Varianten in Ihrer Frage, test.getArray().remove(0)
und aVar.remove(0)
. Es gibt keinen Unterschied in den Ergebnissen von diesen, es ist immer noch nur ein paar Zeiger-ähnliche Referenz und es verändert das Original.
Sie erhalten niemals einen Klon, indem Sie nur einen Getter aufrufen. Wenn das Objekt also nicht unveränderbar ist, können Sie das Objekt ändern, auf das der Getter Ihnen Zugriff gewährt hat. Zum Beispiel ist String
unveränderlich, jede Basis Collection
(einschließlich ArrayList
) ist veränderbar. Sie können Collections.unmodifiable*(...)
aufrufen, um eine Sammlung nicht änderbar zu machen. Wenn die Sammelobjekte jedoch änderbar sind, können sie immer noch geändert werden.
In einigen Fällen ist es ratsam, einen Klon zu erstellen, in den meisten Fällen jedoch nicht. Ein Getter sollte überhaupt nichts klonen, er sollte nicht einmal Daten verändern, es sei denn, er initialisiert eine möglicherweise Null-Sammlung oder etwas Ähnliches. Wenn Sie eine unveränderbare Sammlung mit unveränderbaren Objekten wünschen, versuchen Sie es auf diese Weise. In diesem Beispiel haben wir eine Klasse FooImpl
, die die Schnittstelle Foo
implementiert, die Gründe, die später erklärt werden.
public interface Foo {
int getBar();
}
public class FooImpl Foo {
private int bar;
@Override
public int getBar() {
return bar;
}
public void setBar(int newValue) {
this.bar = newValue;
}
}
Wie Sie sehen, hat Foo keinen Setter. Wenn Sie einige ArrayList<Foo>
erstellen und es von einem Getter als Collections.unmodifiableList(myArrayList)
übergeben, scheint es fast, dass Sie es getan haben. Aber die Arbeit ist noch nicht getan. Wenn die Klasse FooImpl
öffentlich ist (was in diesem Fall der Fall ist), könnte jemand versuchen, wenn das foo
, das er in der Liste gefunden hat, ein instanceof FooImpl
ist, und dann als (FooImpl) foo
wandeln, was es veränderbar macht. Wir können jedoch alle Foo
in einen Wrapper namens FooWrapper
einpacken. Es implementiert Foo
auch:
public class FooWrapper implements Foo {
private Foo foo;
public FooWrapper(Foo foo) {
this.foo = foo;
}
public int getBar() {
return foo.getBar();
}
// No setter included.
}
Dann haben wir eine new FooWrapper(myFoo)
in eine Collection<FooWrapper>
setzen können. Dieser Wrapper hat keinen öffentlichen Setter und der Foo-Inside ist privat. Sie können die zugrunde liegenden Daten nicht ändern. Jetzt über diese Foo
Schnittstelle. Sowohl FooImpl
als auch FooWrapper
implementieren es, wenn eine Methode nicht beabsichtigt, die Daten zu ändern, kann es Foo
auf Eingabe fragen. Es spielt keine Rolle, welche Foo
Sie bekommen.
Wenn Sie also eine nicht änderbare Sammlung mit nicht änderbaren Daten wünschen, erstellen Sie eine neue Collection<Foo>
, füttern Sie sie mit FooWrapper
Objekte und rufen Sie dann Collections.unmodifiable*(theCollection)
. Oder die eigene Sammlung machen, die die ganze Sammlung von Foo Wraps, Rückkehr FooWrappers, zum Beispiel dieser Liste:
public MyUnmodifiableArrayList implements List<Foo> {
ArrayList<Foo> innerList;
public get(int index) {
Foo result = innerList.get(index);
if (!(result instanceof FooWrapper)) {
return new FooWrapper(result);
}
return result; // already wrapped
}
// ... some more List interface's methods to be implemented
}
Mit gewickelter Sammlung, Sie müssen nicht durch die ursprüngliche Sammlung iterieren und machen ihren Klon mit Wrapper von Daten. Diese Lösung ist viel besser, wenn Sie es nicht vollständig lesen, aber es erstellt einen neuen FooWrapper jedes Mal, wenn Sie get()
darauf aufrufen, es sei denn, der Foo auf diesem Index ist bereits ein FooWrapper
. In einem lang laufenden Thread mit Millionen von Aufrufen an get()
könnte dies ein unnötiger Benchmark für den Garbage Collector werden, wodurch Sie ein inneres Array oder eine Karte verwenden, die bereits existierende FooWrappers enthält.
Jetzt können Sie die neue, benutzerdefinierte List<Foo>
zurückgeben. Aber wieder, nicht von einem einfachen Getter. Machen Sie es so ähnlich wie getUnmodifiableFooList()
für Ihre private ArrayList<FooImpl> fooList
Feld.
Java kopiert nie Objekte. – SLaks
Wo ändert sich in diesem Beispiel ein Getter ein Objekt? – raina77ow
Es scheint einfach zu überprüfen. Im Wesentlichen werden in Ihrem Beispiel nur Referenzen übergeben, so dass die Änderungen das ursprüngliche Array betreffen. – assylias