关于Java:保护ArrayList 不受写入访问的影响

Protect ArrayList from write access

考虑以下类别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Cars extends Observable{

    private ArrayList<String> carList = new ArrayList<String>();

    public void addToCarList(String car){
        // ...
        hasChanged();
        notifyObservers();
    }

    public void removeFromCarList(String car){
        // ...
        hasChanged();
        notifyObservers();
    }

    public ArrayList<String> getCarList() {
        return carList;
    }    
}

正如你所看到的,每当Carlist改变时,我想通知Observers。如果有人做了getCarList().add(...);,这是规避的。

除了特殊的方法addToCarListremoveFromCarList,我如何授予对carList的读访问权(用于对它进行迭代等),但阻止对它的写访问?

我想到了:

1
2
3
public ArrayList<String> getCarList() {
    return (ArrayList<String>)carList.clone();
}

但是,当有人使用我的类向carList的克隆体添加某些内容时,他不会被告知这不是该做的事情。


您可以返回不可修改的视图,将返回类型更改为List,而不是ArrayList

1
2
3
public List<String> getCars() {
    return Collections.unmodifiableList(carList);
}

请注意,由于Collections.unmodifiableList只提供了一个视图,调用方仍将看到通过addToCarListremoveFromCarList所做的任何其他更改(我可能将其重命名为addCarremoveCar)。这就是你想要的吗?

返回视图上的任何变化操作都将导致UnsupportedOperationException


首先,总是避免在赋值的左侧使用具体的类,并将其作为方法的返回值。所以,把你的课改成

1
2
3
4
5
6
7
8
9
public class Cars extends Observable{

    private List<String> carList = new ArrayList<String>();
    ........................

   public List<String> getCarList() {
        return carList;
   }
}

现在您可以使用Collections.unmodifiableList()使您列出只读:

1
2
3
   public List<String> getCarList() {
        return Collections.unmodifiableList(carList);
   }

顺便说一句,如果你真的不需要归还List,你可以归还Collection,甚至Iterable。这将提高代码的封装级别,并使以后的修改更加容易。


乔恩·斯基特的回答非常好(一如既往),但它没有涉及到的一件事是并发性问题。

如果多个线程同时访问这个对象,返回不可修改的集合仍然会给您带来问题。例如,如果一个线程正在遍历汽车列表,然后同时另一个线程添加一张新卡。

您仍然需要以某种方式同步对该列表的访问,这也是您可能考虑返回该列表的clone()的原因之一,也可以考虑将其包装在unmodifiableList包装中,而不只是将其包装在unmodifiableList包装中。您仍然需要在clone()周围进行同步,但是一旦克隆完成,并且列表返回到查询代码,就不再需要同步。


我认为,如果对象实际上是一个可观察列表,那么您可以让它实现集合接口。它是一个列表,应该是可观察的——所以它应该实现两个接口。

您甚至可以扩展列表<..>因为您只想向当前功能添加额外的功能(观察者),并且您的列表可以在任何可以使用普通列表的地方使用…


使用collections.unmodifiablelist(list)因为它提供了一个无法修改的新列表对象,所以在尝试更新/添加/删除对象列表时,它将引发一个unsupportedOperationException。