从一到十的等级,从安全编程实践的角度来看,以下情况有多糟糕?如果你发现它比五更糟糕,你会怎么做?
我下面的目标是将 B 中 map 列表中的数据获取到 A 中。在这种情况下,对我来说,无论是数据的副本还是对原始数据的引用都可以。我发现下面的方法最快,但我对此感到不安。
public class A {
private List<Map<String, String>> _list = null;
public A(B b) {
_list = b.getList();
}
}
public class B {
private List<Map<String, String>> _list = new ArrayList<Map<String, String>>();
public List<Map<String, String>> getList() {
// Put some data in _list just for the sake of this example...
_list.add(new HashMap<String, String>());
return _list;
}
}
最佳答案
潜在的问题有点复杂:
- 从安全角度来看,这非常非常糟糕。
- 从性能的角度来看,这非常非常好。
- 从测试的角度来看,这很好,因为类里面没有您无法通过测试轻松获得的内容
- 从封装的角度来看,这很糟糕,因为您暴露了类的内部状态。
- 从编码安全的角度来看,这很糟糕,因为有人最终会滥用它来实现一些“巧妙”的技巧,这会在其他地方导致奇怪的错误,而您将浪费大量时间来调试它。
- 从 API 的角度来看,它可以是:很难想象 API 会更简单,但与此同时,它不会传达您的意图,如果您需要更改基础数据,事情就会严重崩溃结构。
在设计软件时,您需要牢记所有这些要点。随着时间的推移,您会感觉到自己犯了哪些错误以及如何避免这些错误。计算机既笨又慢,从来没有完美的解决方案。你可以努力让它在你写的时候尽可能地好。
如果您想进行防御性编码,您应该始终复制您获得或公开的任何数据。当然,如果“数据”是您的整个数据模型,那么您根本无法在每次调用方法时都复制所有内容。
这个死锁的解决方案:
尽可能多地使用不可变对象(immutable对象)。不可变对象(immutable对象)和值对象被创建并且之后永远不会改变。这些总是安全的,除非创建非常昂贵,否则性能还可以。懒惰的创作在这里会有所帮助,但这通常是它自己的蠕虫 jar 头。 Guava 提供了一套全面的集合,创建后无法更改。
不要过分依赖
Collections.unmodifiable*
,因为后备集合仍然可以更改。使用写时复制数据结构。如果底层列表会在 A 或 B 开始更改它时立即克隆自身,那么上述问题就会消失。这将使每个副本都有自己的副本,从而有效地将它们彼此隔离开来。遗憾的是,Java 不支持这些内置功能。</p>
关于java - 为类(class)成员提供对另一个类(class)成员的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8756085/