保护ArrayList不受写访问

时间:2014-07-08 08:51:44

标签: java

考虑以下课程:

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(...);,则会被规避。

如何为carList提供读取权限(用于迭代等等),但是除了特殊方法addToCarListremoveFromCarList之外,阻止对它的写访问权限?

我想到了这个:

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

但有人使用我的课程,在向carList的克隆添加内容时,不会被告知这不是它的意图。

5 个答案:

答案 0 :(得分:40)

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

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

请注意,由于Collections.unmodifiableList 仅提供视图,调用者仍会看到通过addToCarListremoveFromCarList进行的任何其他更改(我和#39; d可能重命名为addCarremoveCar。这就是你想要的吗?

对返回的视图进行任何变更操作都会产生UnsupportedOperationException

答案 1 :(得分:13)

首先,始终避免在赋值左侧使用具体类,并作为方法的返回值。所以,修改你的课程

public class Cars extends Observable{

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

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

现在,您可以使用Collections.unmodifiableList()将列表设为只读:

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

顺便说一句,如果你真的不必返回List,你可以返回Collection甚至Iterable。这将增加代码的封装级别,并使未来的修改更容易。

答案 2 :(得分:9)

Jon Skeet的回答非常好(一如既往),但它没有触及的一件事是并发问题。

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

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

答案 3 :(得分:2)

我认为你可能会让你的Object实现Collection-Interface,如果它实际上是一个ObservableList。它是一个List,它应该是Observable - 所以它应该实现两个接口。

你甚至可以扩展名单&lt; ..&gt;因为你只想在当前功能中添加额外的功能(观察者),你的List可以在任何可以使用普通List的地方使用......

答案 4 :(得分:0)

使用Collections.unmodifiableList(list),因为它提供了一个无法修改的新List对象,在尝试更新/添加/删除对象列表时会抛出UnsupportedOperationException。