我正在编写一些处理HTTP响应头的代码(一旦填充了一个不可变的集合),并发现自己的代码如下:
private Map<String,String> headers;
public ctor() {
this.headers = new Hashtable<String,String>();
// ... some more ... (actually, this fills this.headers based on ctor parameters)
}
public Map<String,String> getResponseHeaders() {
Map<String,String> temp = new Hashtable<String,String>();
temp.putAll(this.headers);
return temp;
}
看着这个,我发现虽然我知道现在headers
的类型,但不可否认的是,这个课程足够短(目前总共约50行,而不是准备增长更多)在这种特殊情况下它不是一个主要问题,如果问题空间有点复杂,那么在getResponseHeaders()
我可能不知道this.headers
的类型(使用实例化为此特定示例中的名称)。此外,在我想要返回集合副本的大型类中,跟踪许多不同的实例成员变量及其类型(可能由许多因素决定;列表大小会在一个可能< / em>考虑)会变得非常毛茸茸。
两个相关问题:
如果没有完整的依赖注入框架,并且禁止全面使用反射(由于性能损失),是否有任何方法可以使temp
的实例类型与实例类型相同对于一般情况,如上所述的代码this.headers
?
是否存在realistically可能产生重大影响的任何情况?
答案 0 :(得分:2)
您可以致电this.headers.clone()
,但需要投出结果。此外,这仅适用于类型是可复制的情况,并且克隆完全符合您的要求(例如,在这种情况下是浅克隆)。
除此之外,没有可能,因为访问this.headers
的运行时类型(你称之为实例类型)已经涉及反射。但是,我不会因为有人说它很慢而不使用反射。并非所有的反射操作都很慢(例如,我希望在一个对象上调用getClass()
非常快。),并不是你执行的所有操作都会在你的应用中产生性能差异。这取决于更多因素,即执行此操作的频率,优化程序的优势等等。
反射问题更多的是没有通用的方法来实例化特定类型。如果类需要构造函数参数,则需要知道要将哪些对象传递给构造函数。
所以,想一想:你真的需要确保它是完全相同的运行时类型吗?通常情况并非如此。对接口进行编程的全部要点是,您通常不应该关心实际的运行时类型,而只关心它实现了正确的接口(这里是Map
)。因此,即使this.headers
的运行时类型在将来实际上是TreeMap
,其当前形式的getter也会没问题。
然而,在这个特定情况下,我会提出一个完全不同的解决方案。我认为在每次调用getResponseHeaders
时创建整个集合的副本并不好(我猜这比反射方法调用要昂贵得多)。相反,您只需将不可修改的集合视图传递给调用者即可。使用此无法修改的视图,调用者将无法更改您的集合,这通常是您要确保的。所以通常不需要复制整个集合。
通过将getter方法更改为
,可以非常轻松地完成此操作return java.util.Collections.unmodifiableMap(this.headers);
请注意,如果您在调用this.headers
后更改getResponseHeaders
,则调用者会看到地图的更改。