[英]Is it more efficient to use the class, e.g. Hashtable than the interface, e.g. Map?
如果编译器知道它将与接口一起使用的实际类,它会生成更好的代码吗?
例如,我像这样引用我的实际类:
Hashtable<String,String> foo() {
Hashtable<String,String> table = new Hashtable<String,String>(100);
....
return table;
}
...
Hashtable<String,String> tbl = foo();
VS
Map<String,String> foo() {
Map<String,String> table = new Hashtable<String,String>(100);
....
return table;
}
...
Map<String,String> tbl = foo();
第一种形式会更有效吗?
好的,现在总结一下答案。 我希望我能把Thomas和Tagir都标记为正确,但我不能。
托马斯是正确的,因为“正确”行为是使用抽象接口(Map)而不是具体实现(Hashtable)。 这是对数据的适当抽象,并允许随意更改底层实现。
Tagir是正确的,暴露具体类允许某些编译器优化 - 可能是非常重要的优化。 但是,知道这是否有效需要了解编译器内部或基准测试,并且不可移植。 它可能不适用于Android。
最后,如果您关心性能,请不要使用Hashtable; 这是过时和笨重的。 如果您真的关心性能,请考虑使用数组。
就运行时效率而言,两者应该相等,因为在两种情况下都使用Hashtable
。
在设计方面,使用Map
在大多数情况下会更好,即与使用Map
哪个实现无关。 通常,您应该尽可能使用接口,以便替换实现,例如使用HashMap
。
例如, Hashtable
和HashMap
之间的区别主要是由于线程安全,即Hashtable
是同步的,因此线程安全,而HashMap
由于缺乏同步而产生更好的性能。 如果你在界面中使用Map
,你也可以使用ConcurrentHashMap
而不必更改调用者并获得线程安全性和性能(虽然我不确定ConcurrentHashMap
和Hashtable
之间会有多大差异)。
除了使用Hashtable
本身是对性能的犯罪(获取每个方法调用的锁定)这一事实之外,使用具体类的优势只会给非JIT编译的代码带来轻微优势,因为可以访问类的vtable直接,而不是通过itable查找数组的线性搜索,加上对实际itable的解引用。 只有当一个类实现了许多接口时,这种搜索的开销才会变得很重要,而Hashtable
则不然。
除非您的调用站点调度到许多不同的Map
实现(几乎不可能),否则JIT编译的代码将像在变量上使用具体类型一样高效。 对于你说的最简单的情况
Map<K,V> m = new Hashtable<>();
甚至解释器也可以静态地确定m
将始终指向Hashtable
并相应地进行优化。
有时返回具体类可能会提高性能。 例如,考虑从地图中获取内容:
Map<String,String> tbl = foo();
String result = tbl.get(something);
如果tbl
是像Hashtable
这样的具体类(并且你没有重载get
方法的Hashtable
子类),那么对方法的调用可以很容易地被虚拟化甚至内联(这甚至可以通过更简单的C1“客户端”编译器来完成) 。 如果您使用该接口,它将更难以虚拟化。 据我所知,C1根本无法使用多个实现器来虚拟化接口调用。 C2“server | compiler可以做到,但它应该依赖于类型配置文件。因此你的代码应该足够热,并且配置文件不应该被其他类型污染。
然而,在某些特定的基准测试中,这种差异可能是数量级的,在大多数生产代码中,这是可以忽略的,并且不太可能成为性能瓶颈。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.