保护ArrayList不受写入权限的限制

考虑以下课程:

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的克隆添加某些carList ,不会被告知这不是它意味着完成的方式。


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

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

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

对返回视图的任何变异操作都将导致UnsupportedOperationException


首先,总是避免在赋值左侧使用具体类并作为方法的返回值。 所以,请将你的课程修复为

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 。 这将增加代码的封装级别,并使未来的修改更容易。


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

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

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

链接地址: http://www.djcxy.com/p/53927.html

上一篇: Protect ArrayList from write access

下一篇: Why List<String> is not acceptable as List<Object>?