3

我有一个 X 对象,其构造函数接受 4 个整数字段。为了计算它的哈希函数,我简单地将它们放入一个数组中并使用 Arrays.hashCode。

目前构造函数是私有的,我有一个静态的创建者方法。我想记住构造,以便每当使用之前调用的 4 个整数参数调用创建者方法时,我都可以返回与上次相同的对象。[理想情况下,无需创建另一个 X 对象进行比较。]

最初我尝试了一个 hashSet,但这需要我创建一个新的 X 来检查我的 hashSet.contains 是否包含相等的对象......不要介意我无法从 hashSet 中“得到”的事实。

我的下一个想法是使用 HashTable 映射:4 个字段的 int 数组的 hashCode --> 对象。我不知道为什么,但感觉不对。感觉好像我做的工作太多了,hashCode 的意义不就是映射到一堆计算到相同 hashCode 的对象吗?

我很感激你的建议。

4

3 回答 3

3

哈希码的目的通常是缩小查找特定对象的位置。或者换一种说法,这个想法是你的哈希码使得如果两个对象具有相同的哈希码,它们“很可能”是同一个对象。

现在,“非常可能”的可能性有多大基本上取决于哈希码的宽度(位数)和质量。在 Java 的情况下,使用 32 位哈希码,这个“很可能”仍然通常意味着“还没有接近 100%,您可以取消对象数据的实际比较”。因此,除了实现 hashCode() 之外,您还需要在用作 Java Map(HashMap 等)的键的对象上实现 equals()。

或者换一种说法:你的实现基本上是正确的,即使看起来你做了很多工作。结果是,如果您正在寻找的是性能改进,那么您不妨每次都创建一个新对象。但是,如果在功能上您要求不存在多个具有给定值的对象,那么您的实现基本上是正确的。

原则上你可以做的事情:

  • 如果您有大量整数,那么对于 hashCode(),只需从其中几个“样本”中形成哈希码——想法是“缩小选择范围”或使其“公平但不100% 可能'相等的哈希码意味着相等的对象——你的 equals() 无论如何都必须检查它们,所以循环遍历 hashCode() 和 equals() 中的所有值没有意义;
  • 潜在地,您可以使用更强的哈希码,以便您从字面上假设相等的哈希码意味着相等的对象。实际上,您在哈希码函数中循环遍历所有值一次,并且根本没有 equals 函数。在实践中,这意味着至少使用强 64 位哈希码。对于您提到的情况,这可能不值得。但是,如果您想稍微了解一下它的工作原理,我会向您介绍我写的关于Java 中哈希码的高级使用的教程。
于 2012-11-25T06:27:34.180 回答
1

如果构造过程中的 4 个整数意味着生成的对象将完全相同,则使用它们作为键,而不是它们的散列。请注意,我没有使用您的完整对象作为键,只是使用 4 个整数值。下面的 MyObjectSpecification 将是一个小对象。

public class MyObjectSpecification {
    private final int i1, i2, i3, i4;

    public MyObjectSpecification(int i1, int i2, int i3, int i4) {
        this.i1 = i1;
        this.i2 = i2;
        this.i3 = i3;
        this.i4 = i4;
    }

    public boolean equals(Object o) {
        // ...
    }

    public int hashCode() {
        // ...
    }
}

public class MyObject {
    private static final Map<MyObjectSpecification, MyObject> myObjects
            = new ConcurrentHashMap<MyObjectSpecification, MyObject>();

    private MyObject(MyObjectSpecification spec) {
        // ...
    }

    public static MyObject getMyObject(int i1, int i2, int i3, int i4) {
        MyObjectSpecification spec = new MyObjectSpecification(i1, i2, i3, i4);

        if (myObjects.containsKey(spec)) {
            return myObjects.get(spec);
        }

        MyObject newObject = new MyObject(spec);
        myObjects.put(spec, newObject);
        return newObject;
    }
}
于 2012-11-25T07:34:56.157 回答
0

不确定您打算如何使用 Hashtable,但我认为以下内容可以完成您的工作:

    private static Hashtable<Integer, MyObject> objectInstances = 
             new Hashtable<Integer, MyObject>();


    public static MyObject instance(int i1, int i2, int i3, int i4){
         int hashKey = Arrays.hashCode(new int[]{i1, i2,i3,i4});
         //get the object from hashtable
         MyObject myObject = objectInstances.get(hashKey);

         //if object was not already created, create now and put in the hashtable
         if(myObject == null){
           myObject = new MyObject(i1,i2,i3,i4);
           objectInstances.put(hashKey, myObject);
         }
        return myObject;
    }
于 2012-11-25T06:22:57.097 回答