在 Java 7 HashMap
实现中,在 resize
方法中,它调用 transfer
将旧元素移动到新表。为什么他们编写了一个新方法而不是使用所有旧元素调用 put
?由于 threshold,不会再次触发调整大小。调用 put
使代码更清晰。
/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
答案 0 :(得分:5)
一个重要的区别是 dynamic_cast
可以通过两种方式利用每个条目已经存在 template <typename To, typename From>
To fastest_cast( From && from );
struct A { virtual ~A() = default; };
struct B : A {};
struct C : virtual A {};
int main()
{
B b;
fastest_cast<B*>( (A*)&b ); //expected static_cast inside
C c;
fastest_cast<C*>( (A*)&c ); //expected dynamic_cast inside
}
对象这一事实:
fastest_cast
对象本身以避免必须分配新对象(从而避免内存分配,从而降低 GC 压力)。bidId
对象中的 transfer
值,从而避免必须对地图中已有的每个键调用 Entry
(理论上这可能是一项昂贵的操作)。 基本上:如果仅根据 Entry
实现 hash
,则必须重新做很多很容易避免的工作。
JDK 的更高版本具有明显更复杂的 Entry
实现,其中实现了更复杂的 Object.hashValue
方法(或等效方法)。
还值得指出的是,在 JDK 本身中完成时,即使以不那么“简单”的代码为代价的微小性能提升通常也是值得的:因为 resize
基本上用于那里的每个 Java 程序,具有以稍微降低可读性为代价尽可能提高性能通常是值得的权衡。同样的推理不同样适用于我们“凡人”编写的大多数其他软件。