正如其他人所说,除非它是原始类型,否则您将获得对该对象的引用。它类似于 C++ 中的指针,它允许您访问对象,但与 C++ 引用(指向变量的内存地址的指针)不同,它不允许您将其替换为另一个对象。只有二传手才能做到这一点。
我在您的问题中看到了两个变体,test.getArray().remove(0)
并且aVar.remove(0)
. 这些结果没有区别,它仍然只是一些类似指针的引用,它修改了原始引用。
您永远不会通过调用 getter 来获得克隆,因此除非对象是不可变的,否则您可以修改 getter 允许您访问的对象。例如,String
是不可变的,任何基本的Collection
(包括ArrayList
)都是可变的。您可以调用Collections.unmodifiable*(...)
以使集合不可修改。但是,如果集合项是可变的,它们仍然可以更改。
在某些情况下,获得克隆是个好主意,但在大多数情况下并非如此。getter 根本不应该克隆任何东西,它甚至不应该修改数据,除非它初始化一个可能为空的集合或类似的东西。如果您想要一个包含不可变对象的不可修改集合,请尝试这样做。在这个例子中我们有一个FooImpl
实现接口的类,Foo
后面会解释原因。
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;
}
}
如您所见, Foo 没有二传手。如果你创建一些ArrayList<Foo>
并从一些 getter 传递它Collections.unmodifiableList(myArrayList)
,几乎看起来你做到了。但这项工作还没有完成。如果该类FooImpl
是公共的(在这种情况下是公共的),那么有人可能会尝试如果foo
他在列表中找到的是 aninstanceof FooImpl
然后将其转换为(FooImpl) foo
使其可变。但是,我们可以将任何Foo
内容包装到一个名为FooWrapper
. 它也实现Foo
了:
public class FooWrapper implements Foo {
private Foo foo;
public FooWrapper(Foo foo) {
this.foo = foo;
}
public int getBar() {
return foo.getBar();
}
// No setter included.
}
然后我们可以将 anew FooWrapper(myFoo)
放入 aCollection<FooWrapper>
中。这个包装器没有任何公共设置器,里面的 foo 是私有的。您不能修改基础数据。现在关于那个Foo
界面。两者都FooImpl
实现FooWrapper
它,如果任何方法不打算修改数据,它可以要求Foo
输入。Foo
你得到哪个并不重要。
因此,如果您想要包含不可修改数据的不可修改集合,请创建一个新的Collection<Foo>
,用FooWrapper
对象提供它,然后调用Collections.unmodifiable*(theCollection)
. 或者制作一个自定义集合来包装整个 Foo 集合,返回 FooWrappers,例如这个列表:
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
}
使用包装的集合,您不必遍历原始集合并使用数据包装器对其进行克隆。当您不完整阅读它时,此解决方案要好得多,但是每次调用get()
它时它都会创建一个新的 FooWrapper ,除非该索引上的 Foo 已经是FooWrapper
. 在具有数百万次调用的长期运行线程中get()
,这可能成为垃圾收集器不必要的基准,使您使用一些包含现有 FooWrappers 的内部数组或映射。
现在您可以返回新的 custom List<Foo>
。但同样,不是来自普通的吸气剂。让它像getUnmodifiableFooList()
你的private ArrayList<FooImpl> fooList
领域一样。