我在我的项目上运行了Findbug工具,它发现了18个类型的问题:
存储对可变对象的引用 - > 可以通过合并对可变对象的引用来公开内部表示
所以我有一个类,构造函数接受Object类型的数组并将其分配给私有类成员变量。这是一个例子:
public Class HtmlCellsProcessing extends HtmlTableProcessing
{
private Object[] htmlCells;
public HtmlCellsProcessing(Object[] htmlCells)
{
this.htmlCells = htmlCells;
}
}
以下是有关警告的进一步说明:
此代码将对外部可变对象的引用存储到对象的内部表示中。如果不受信任的代码访问实例,并且对可变对象的未经检查的更改会危及安全性或其他重要属性,则需要执行不同的操作。在许多情况下,存储对象的副本是更好的方法。
他们给我的建议非常明显,但是如果数组的大小非常大,并且如果我将其值复制到成员变量数组中,则应用程序将占用两倍的内存。
在我拥有大量数据的情况下,我该怎么办?我应该将其作为参考传递还是一直复制?
答案 0 :(得分:2)
这取决于。您有多个问题,包括空间,时间和正确性。
防御性副本可帮助您保证列表项在不知道持有数组的类的情况下不会更改。但它需要O(n)时间和空间。
对于非常大的阵列,您可能会发现防御性副本在空间和时间上的成本对您的应用程序有害。如果你控制所有可以访问数组的代码,那么在没有防御性副本的情况下保证正确性是合理的,并且在该类上禁止FindBugs警告。
答案 1 :(得分:1)
我建议你尝试使用guava库中的不可变列表。见http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained
答案 2 :(得分:1)
如果需要封装和性能,典型的解决方案是将引用传递给不可变对象。
因此,不是直接传递一个巨大的数组,而是将其封装在一个不允许数组修改的对象中:
final class ArraySnapshot {
final Object[] array;
ArraySnapshot(Object[] array) {
this.array = Arrays.copyOf(array);
}
// methods to read from the array
}
这个对象现在可以廉价地传递,但由于它是不可变的,因此可以确保封装。
这个想法,当然,如果没有什么新内容:这是String
对char[]
的作用。
答案 3 :(得分:0)
他们给我的建议非常明显,但是如果有的话会发生什么 数组的大小非常大,如果我将其值复制到成员中 变量数组应用程序将占用两倍的内存。
在Java中,除非您进行深层复制,否则复制引用不会自行对象 因此,如果你唯一关心的是摆脱警告(这是有效的,特别是如果你不明白你实际存储的是什么,并且你有多个线程修改对象),你可以做一个副本,而不需要太多关注内存。< / p>