Java HashMap或IdentityHashMap

Java HashMap或IdentityHashMap,java,Java,在某些情况下,map中使用的键对象不会覆盖Object中的hashCode()和equals(),例如,使用套接字连接或java.lang.Class作为键 将这些对象用作HashMap中的键是否存在任何潜在缺陷 在这些情况下我应该使用IdentityHashMap吗 据我所知,使用坏键的hashmap的唯一问题是使用非常大的hashmap—您的键可能非常坏,您得到的是o(n)检索时间,而不是o(1)。如果它确实破坏了其他任何东西,我很想听听:)如果在关键对象上没有覆盖equals()和hash

在某些情况下,map中使用的键对象不会覆盖Object中的hashCode()和equals(),例如,使用套接字连接或java.lang.Class作为键

  • 将这些对象用作HashMap中的键是否存在任何潜在缺陷
  • 在这些情况下我应该使用IdentityHashMap吗

  • 据我所知,使用坏键的hashmap的唯一问题是使用非常大的hashmap—您的键可能非常坏,您得到的是o(n)检索时间,而不是o(1)。如果它确实破坏了其他任何东西,我很想听听:)

    如果在关键对象上没有覆盖
    equals()
    hashCode()
    ,HashMap和IdentityHashMap应该具有相同的语义。默认的equals()实现使用引用语义,默认的
    hashCode()
    是对象的系统标识哈希代码

    只有当一个对象的不同实例在逻辑上是相等的时,这才是有害的。例如,如果您的密钥是:

    new Integer(1)
    

    因为它们在技术上是Integer类的不同实例。(您确实应该使用
    Integer.valueOf(1)
    ,但这偏离了主题。)

    Class
    作为键应该是可以的,除非在非常特殊的情况下(例如,hibernate ORM库在运行时生成类的子类以实现代理)。作为开发人员,我对将
    Connection
    对象存储在映射中作为键的代码持怀疑态度(如果您正在管理数据库连接,也许您应该使用连接池?)。它们是否有效取决于实现(因为连接只是一个接口)


    另外,需要注意的是,HashMap期望
    equals()
    hashCode()
    的确定保持不变在key对象上使用可变字段,更改key字段可能会使key在HashMap的错误hashtable bucket中“丢失”。在这种情况下,您可以使用IdentityHashMap(取决于对象和特定用例),或者您可能只需要不同的
    equals()/hashCode()
    实现。

    在您描述的情况下,HashMap和IdentityHashMap的行为是相同的

    与此相反,如果键覆盖equals()和hashCode(),则两个映射的行为是不同的

    请参见下面java.util.IdentityHashMap的javadoc

    此类使用哈希表实现映射接口,在比较键(和值)时使用引用相等代替对象相等。换句话说,在IdentityHashMap中,两个键k1和k2被视为相等当且仅当(k1==k2)。(在正常映射实现中(如HashMap)两个键k1和k2被认为是相等的当且仅当(k1==null?k2==null:k1.equals(k2)))

    总之,我的答案是:

  • 将这些对象用作HashMap中的键是否存在任何潜在缺陷? -->
  • 在这些情况下我应该使用IdentityHashMap吗?-->

  • 虽然理论上没有问题,但除非您有明确的理由使用它,否则应该避免使用
    IdentityHashMap
    。在一般情况下,当您不可避免地开始向映射中引入覆盖
    equals()
    hashCode()的对象时,它不会提供明显的性能或其他好处
    ,您最终会发现一些微妙的、难以诊断的错误


    如果出于性能原因,您认为需要
    IdentityHashMap
    ,那么在切换之前,请使用探查器确认您的怀疑。我的猜测是,您将发现大量其他优化机会,这些机会既更安全,也会产生更大的影响。

    从移动代码安全的角度来看,在某些情况下,using
    IdentityHashMap
    或类似的方法是必要的。非
    final
    关键类的恶意实现可以覆盖
    hashCode
    equals
    为恶意类。例如,它们可以声明不同实例的相等性,获取对它们所比较的其他实例的引用,等等。我建议打破通过保持安全并在需要标识语义的地方使用
    IdentityHashMap
    的标准做法。在已经比较超类的子类中,很少有很好的理由更改相等的含义。我猜最有可能的情况是一个损坏的非对称代理


    IdentityHashMap
    的实现与
    HashMap
    大不相同。它使用线性探测而不是
    Entry
    对象作为链中的链接。这导致对象的数量略有减少,尽管总内存使用量差异非常小。我没有任何可以提供的良好性能统计数据引用。使用(非重写)和
    Object.hashCode
    System.identityHashCode
    ,但这在几年前就被清除了。

    你的意思是糟糕的hashCode方法,不是吗?吹毛求疵-在一般情况下
    ==
    System.identityHashCode
    比典型的重载
    equals
    方法要快。但我同意t这通常不是使用
    IdentityHashMap
    而不是
    HashMap
    的好理由@Stephen C:很公平——我添加了一条免责声明。:)
    new Integer(1)