0

我的程序中有以下代码:

...
private void generateStack() {
    List<AdvertisementsModel> adsForModel = Storage.getAdsForId(model.getId());
    ...
    adsForModel.clear();
...

Storage是具有静态字段和方法的静态类。generateStack方法在另一个类和实例对象中。如果引用不是最终的,为什么会adsForModel.clear();影响类中的列表?StorageasdForModel

4

4 回答 4

3

Storage.getAdsForId(...)返回对同一List对象的引用的副本。所以通过这个引用调用相同的列表。当您调用Storage.getAdsForId时,不会创建新列表 - 只是对同一列表的新引用。

因此,显式返回ImmutableList或制作列表的防御性副本Storage.getAdsForId(...)并返回副本是一种很好的做法。

请注意,当AdvertisementsModel可变时您需要进行深层复制,否则您将在不同级别遇到相同的问题。(否则,您现在可能有一个列表副本,但两个列表仍然包含对相同AdvertisementsModel对象的引用,并且更改它们仍然会影响内部的列表内容Storage。)

于 2013-03-04T10:07:05.770 回答
3

Java 是按值传递的(引用的)。因此,如果Storage.getAdsForId(model.getId())返回一个静态存储在 Storage 中的引用,那么clear()在实例中调用它也会影响同一个 List Storage。你可以这样做:

return new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));

而是返回列表的副本,这将避免影响存储中的列表。当然,修改这个列表的一个元素仍然会影响Storage. 为避免这种情况,您必须深度复制列表中的每个元素。

于 2013-03-04T10:10:12.217 回答
1

getAdsForId应该返回列表的副本,否则它将返回一个引用并且调用clear列表将清空原始列表。

于 2013-03-04T10:07:27.917 回答
1

如果是final的话,原名单不受影响吗?我对此表示怀疑......这是同一个列表实例。为此,我会使用

new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));

它创建一个新的列表实例,如果可能,修改Storage类以返回原始列表的 UnmofifiableList:

return Collections.unmodifiableList(adsForIdList);

我更喜欢这个,因为这个解决方案不会在每次调用时创建一个新的 List 实例,接收代码有责任决定是否需要创建它。但是,在多线程环境中,如果原始列表可能被修改,这可能会导致ConcurrentModificationExceptions - 因此在这种情况下,在 getter 本身中创建列表的“防御性副本”更为明智。请务必记住,然后对副本的修改不会影响原始列表...

于 2013-03-04T10:11:33.887 回答