正如其他人所说,除非它是原始类型,否则您将获得对该对象的引用。它类似于 C++ 中的指针,它允许您访问对象,但与 C++ 引用(指向变量的内存地址的指针)不同,它不允许您将其替换为另一个对象。只有 setter 才能做到这一点。
我在您的问题中看到了两个变体,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 是否是instanceof 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.
}
然后我们可以将new FooWrapper(myFoo) 放入Collection<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 的内部数组或映射。
现在您可以返回新的自定义 List<Foo>。但同样,不是来自普通的吸气剂。为您的 private ArrayList<FooImpl> fooList 字段设置类似于 getUnmodifiableFooList() 的内容。