3

我在我的项目上运行 Findbug 工具,它发现了 18 个类型的问题:

存储对可变对象的引用->可以通过合并对可变对象的引用来公开内部表示

所以我有一个类,构造函数接受 Object 类型的数组并将其分配给私有类成员变量。这是一个例子:

public Class HtmlCellsProcessing extends HtmlTableProcessing
{
    private Object[] htmlCells;

    public HtmlCellsProcessing(Object[] htmlCells)
    {
        this.htmlCells = htmlCells;
    }
}

以下是有关警告的进一步说明:

此代码将对外部可变对象的引用存储到对象的内部表示中。如果实例由不受信任的代码访问,并且对可变对象的未经检查的更改会危及安全性或其他重要属性,则您将需要做一些不同的事情。在许多情况下,存储对象的副本是更好的方法。

他们给我的建议很明显,但是如果数组的大小非常大并且如果我将其值复制到成员变量数组中,应用程序将占用两倍的内存会发生什么。

在我有大量数据的情况下应该怎么做?我应该将它作为参考传递还是总是复制它?

4

4 回答 4

2

这取决于。您有多个问题,包括空间、时间和正确性。

防御性副本可帮助您确保列表项在不知道持有数组的类的情况下不会更改。但这需要 O(n) 的时间和空间。

对于一个非常大的数组,您可能会发现防御性副本在空间和时间上的成本对您的应用程序是有害的。如果您通过访问数组来控制所有代码,那么在没有防御性副本的情况下保证正确性并抑制该类的 FindBugs 警告可能是合理的。

于 2013-03-25T22:07:52.777 回答
1

我建议你尝试使用 guava 库中的不可变列表。请参阅http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained

于 2013-03-25T21:30:48.593 回答
1

如果同时需要封装和性能,典型的解决方案是传递对不可变对象的引用。

因此,与其直接传递一个巨大的数组,不如将其封装在一个不允许修改数组的对象中:

final class ArraySnapshot {
    final Object[] array;

    ArraySnapshot(Object[] array) {
        this.array = Arrays.copyOf(array);
    }

    // methods to read from the array
}

这个对象现在可以廉价地传递,但由于它是不可变的,因此可以确保封装。

这个想法,当然,如果没有什么新意的话:它就是Stringchar[].

于 2013-03-25T21:33:47.950 回答
0

他们给我的建议非常明显,但是如果数组的大小非常大并且如果我将其值复制到成员变量数组中,应用程序将占用两倍的内存会发生什么。

在 Java 中,您复制引用而不是对象本身,除非您进行深度复制。
因此,如果您唯一关心的是摆脱警告(这是有效的,但特别是如果您不了解您实际存储的内容并且您有多个线程修改对象),您可以在不担心内存的情况下进行复制。

于 2013-03-25T21:34:22.557 回答