0

我有一个基类MyBase和大约十几个派生类。我在代码中严重依赖访问者模式。所以基类是访问者的抽象宿主,每个派生类都是具体宿主。我正在使用实现IEqualityComparer<MyBase>接口的独立比较器。此接口中有 2 个方法:Boolean Equals(MyBase a, MyBase b)Int32 GetHashCode(MyBase obj). 在这些方法中的每一个中,我都使用一个访问者来将一个实例解析MyBase为一个派生类型的实例。这就是我避免处理铸造的方式。所以访问者是一个需要在每次调用Equalsand时创建的对象GetHashCode。我已经阅读了很多关于保持GetHashCode尽可能便宜的内容,所以问题是:

GetHashCode考虑到性能,在and方法中创建对象(访问者)是Equals一个坏主意吗?

4

2 回答 2

2

问题假设创建一个新对象是昂贵的。它不是。创建一个新对象涉及将堆指针向上移动对象的大小,将这些字节清零,然后调用构造函数。只要构造函数不做任何昂贵的事情,并且有足够的内存用于分配(如果没有,GC 需要运行并且便宜),这将非常快。

与创建新对象相关的“成本”出现在需要收集它们时。创建更多对象意味着您需要更频繁地收集垃圾,因此您将在未来某个不确定的时间点减慢代码速度。话虽如此,除非您要创建大量对象或非常大的对象,并且这些对象的寿命不长,否则这根本不成问题。

于 2013-06-28T20:59:56.917 回答
1

的实现GetHashCode()应该以这样的方式编写,即第一个调用之后的每个调用都会很快。如果计算一个对象的哈希值需要构造一个新对象,这是一个很好的迹象,表明该对象可能应该在计算一次之后缓存哈希值,这样以后对哈希码的请求就可以得到快速响应。请注意,使用标志来指示是否已计算哈希码可能是不值得的。相反,确定零不是有效的哈希码值,并有一个HashCode初始化为零但在计算后被哈希码覆盖的字段。如果哈希码的计算方法将产生零,则替换为其他一些任意值。零和其他值都应该只出现大约 1/4,000,000,000 的时间,因此将其他值的概率加倍到 1/2,000,000,000 应该没什么大不了的。

如果您正在缓存哈希码,那么如果它们的计算有点昂贵,那么它应该没有太大关系,因为它只会执行一次。即使缓存了哈希码,仍然应该尝试使其相当快,但不要太担心。

于 2013-06-29T23:50:15.033 回答