4

我在我的 Java 项目的一个类中使用了 ArrayList。该类跟踪列表是否已更改,并提供公共方法来添加和删除自动将变量设置为“已更改”的列表中的元素。

到目前为止,该列表是公开的,因为我希望我的列表在任何地方都可以公开阅读。但我只希望拥有列表的类能够修改它。所以没有来自外部类的修改。那可能吗?如果是这样,怎么做?

通常对于访问控制,您可能会使用 getter 和 setter 方法。但即使使用 getter 方法并将列表设置为私有,另一个类仍然可以这样做getList().remove(element),从而从外部修改列表,而不会注意到列表已更改。

4

5 回答 5

2

将您的 List 设为私有并添加 getter 方法:

public List getList(){
    return new ArrayList(yourPrivateList);
}
于 2014-12-24T10:52:44.567 回答
2

将您的 ArrayList 字段设为私有,但让您的 getter returnCollections.unmodifiableList(list)提供不可修改的视图。

这将允许外部代码将其视为普通列表,使用 for each 循环等,但将禁用修改操作。此外, unmodifiableList 会在恒定时间内返回一个视图。

这实际上是它设计的确切用例。Java 文档:

此方法允许模块为用户提供对内部列表的“只读”访问权限。对返回列表的查询操作“通读”到指定列表,并尝试修改返回的列表,无论是直接还是通过其迭代器,都会导致 UnsupportedOperationException。

于 2014-12-25T10:28:37.507 回答
1

您可以将ArrayList成员设为私有,而不是返回 . 的 getter,而是使用ArrayList接受索引i并返回i' 的ArrayList

public class Test
{
    private List<String> list = new ArrayList<String>();

    public getString (int i)
    {
        // you might want to add some validation of i here
        return list.get(i);
    }

}

getString允许您的类的用户访问列表中的任何元素,而无需对其进行修改。

如果您想让您的用户在无法修改列表的情况下迭代列表,您可以添加一个getSize()方法来返回列表的大小(这将允许用户使用常规 for 循环迭代列表),或者你的类可以实现Iterable(不支持删除操作)。

于 2014-12-24T10:48:45.927 回答
1

你有几个选择:

  • 返回 ArrayList 的 getter 可以在返回对象之前进行克隆。这样,即使外部实体修改了对象,他们最终也会修改克隆 - 而不是您的原始对象。注意:克隆操作可能代价高昂。我建议以下选项。
  • 使用Collections.unmodifiableList(..). 在此处查看文档。
  • 或者正如其他答案所建议的那样:推出自己的访问和迭代方法。
于 2014-12-24T10:55:18.607 回答
1

我认为您最好的选择是保持您的List 私密性并添加一个 getter 方法,该方法返回 的副本List,但不返回List本身。例如:

public class EncapsulationTest {

    private List<Object> privateList = new ArrayList<Object>();

    // Your constructors and methods to track list
    // modification here ...

    public List<Object> getList() {
        // Maybe you need a null check here
        return new ArrayList<Object>(privateList);
    }

    public void addElement(Object newElement) {
        this.privateList.add(newElement);
        // Set your 'changed' variable to true
    }

    public void removeElement(Object element) {
        this.privateList.remove(element);
        // Set your 'changed' variable to true
    }
}

如果这样做,您仍然可以读取 的精确副本List但不能修改它List本身。好吧,实际上您可以修改返回的List,但由于它是不同的对象,因此更改不会影响您对象的List.

我希望它有所帮助。

于 2014-12-24T11:05:59.493 回答