Java:没有来自外部类的 ArrayList 修改

Posted

技术标签:

【中文标题】Java:没有来自外部类的 ArrayList 修改【英文标题】:Java: No ArrayList modifications from outside classes 【发布时间】:2015-02-22 11:55:57 【问题描述】:

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

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

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

【问题讨论】:

只通过公共函数提供所有需要的功能,完全封装内部数据结构。所以写你自己的删除函数。 【参考方案1】:

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

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

这实际上就是它设计的确切用例。 Javadoc:

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

【讨论】:

【参考方案2】:

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

public List getList()
    return new ArrayList(yourPrivateList);

【讨论】:

【参考方案3】:

您可以将ArrayList 成员设为私有,而不是返回ArrayList 的getter,而是使用一个接受索引i 并返回ArrayList 的第i'th 元素的getter。

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(不支持删除操作)。

【讨论】:

【参考方案4】:

你有几个选择:

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

【讨论】:

【参考方案5】:

我认为您最好的选择是保留您的 List private 并添加一个 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

希望对你有帮助。

【讨论】:

Thrustmaster 在他的回答中提到归还克隆的成本很高。我在启发式中使用列表,其中运行时是最重要的,并且对这些(大)列表的迭代很频繁。

以上是关于Java:没有来自外部类的 ArrayList 修改的主要内容,如果未能解决你的问题,请参考以下文章

Java - 为来自外部库的类定义一个通用接口

对于Hashmap到ArrayList的循环没有保持正确的值。怎么修?

来自 ArrayList 类的列表视图

Java中的get()和set()

来自 DAO 类的 JSTL foreach ArrayList 对象不起作用

number 编译错 (类的大小写错误) Filewriter cannot be resolved to a type