Java 这是生成散列码的好方法吗?

Java 这是生成散列码的好方法吗?,java,hash-code-uniqueness,Java,Hash Code Uniqueness,我必须在以下两种情况下编写哈希函数: 我对传递给方法的对象o一无所知-它可以是字符串、整数或实际的自定义对象 我根本不允许调用hashCode() 我现在使用的方法是计算哈希代码: 将对象写入字节流 将字节流转换为字节数组 循环遍历字节数组并通过如下操作计算哈希: 哈希=哈希*素数+字节数组[i] 我的问题是,这是一个可以接受的方法,有没有改进的方法?就我个人而言,我觉得这个函数的范围太广了——没有关于对象是什么的信息,但我在这种情况下几乎没有发言权。hash=(hash*PRIME+byt

我必须在以下两种情况下编写哈希函数:

  • 我对传递给方法的
    对象o
    一无所知-它可以是字符串、整数或实际的自定义对象
  • 我根本不允许调用
    hashCode()
我现在使用的方法是计算哈希代码:

  • 将对象写入字节流
  • 将字节流转换为字节数组
  • 循环遍历字节数组并通过如下操作计算哈希:


    哈希=哈希*素数+字节数组[i]


  • 我的问题是,这是一个可以接受的方法,有没有改进的方法?就我个人而言,我觉得这个函数的范围太广了——没有关于对象是什么的信息,但我在这种情况下几乎没有发言权。

    hash=(hash*PRIME+byteArray[I])%MODULO?

    此外,当你在使用它时,如果你想尽可能避免冲突,你可以使用标准化的(如果故意冲突是一个问题,则加密)第3步中的散列函数,如SHA-2左右


    请看一看,这也省去了第2步。

    您可以使用,而不是实现自己的解决方案。

    序列化方法只适用于事实上可序列化的对象。因此,对于所有类型的对象都不可能

    此外,这将通过具有等效对象图来比较对象,而等效对象图不一定与通过
    .equals()
    相等的对象图相同

    例如,由相同代码(具有相同数据)创建的StringBuilder对象将具有相等的OOS输出(即,也具有相等的哈希),而
    b1.equals(b2)
    为false,具有相同元素的ArrayList和LinkedList将注册为不同,而
    list1.equals(list2)
    true


    通过创建自定义的
    HashOutputStream
    ,您可以避免将字节流转换为数组步骤,该步骤只需获取字节数据并对其进行散列,而不是将其保存为数组供以后迭代使用

    class HashOutputStream extends OutputStream {
    
        private static final int PRIME = 13;
        private int hash;
    
        // all the other write methods delegate to this one
        public void write(int b) {
            this.hash = this.hash * PRIME + b;
        }
    
        public int getHash() {
            return hash;
        }
    }
    
    然后将ObjectOutputStream包装在此类的对象周围

    代替您的
    y=y*13+x
    方法,您可以查看其他校验和算法。例如,java.util.zip包含
    Adler32
    (用于
    zlib
    格式)和
    CRC32
    (用于
    gzip
    格式).

    看一看非加密哈希。他介绍了许多方法,讨论了它们的优点、缺点以及速度和冲突概率之间的权衡

    如果没有其他原因,它将允许你证明你的算法决定是正确的。向你的导师解释为什么你选择速度而不是正确性,反之亦然

    作为起点,请尝试他的:

    ub4一次一个(char*键,ub4 len)
    {
    ub4散列,i;
    for(hash=0,i=0;i6);
    }
    hash+=(hash>11);
    
    hash+=(hash这听起来像是家庭作业(为什么不允许你调用
    hashCode
    ?)。如果是,请标记它,这样你就可以得到不同(更好)的答案。谢谢,我不知道这个标记存在:)完成。可以完全取消步骤2:)@Blindy我认为他的意思是将字节流转换为字节数组。@Nikita由于您不知道任何对象的详细信息,我认为您是在尽可能最好地进行转换。不是必需的-有一个2^64的隐式模。@mlaw取决于内部表示。但是你是对的,很可能一路
    int
    。修复了“将字节流转换为字节数组”-这样我就可以对其进行迭代。-步骤2显然是一个输入错误,使用任何哈希函数都会抛出唯一性-它是哈希而不是压缩。@Nikita你不需要创建字节数组(这将占用大量内存;大多数哈希函数都被指定为处理短缓冲区流)。用
    DigestInputStream
    @Blindy-Yes更新了答案。这表示得不好。我的意思是相对较低的冲突率(以及使用SHA2或更好的,任何冲突的概率都非常小)(除非密码分析有进步))。更新后的版本仍然不正确吗?正常哈希函数和加密哈希函数之间的主要区别(假设哈希输出大小相同),就是加密的方法可以防止故意的冲突,而普通的散列方法只能防止意外的冲突。而普通的散列方法通常更快。我必须实现我自己的解决方案,这就是问题的关键:)要处理并非所有对象都可序列化的问题,可以使用toString()将对象转换为字符串。看起来该对象正在传递到hashCode方法,因此这不是对象的hashCode方法,因此不必维护equals一致性。
    ub4 one_at_a_time(char *key, ub4 len)
    {
      ub4   hash, i;
      for (hash=0, i=0; i<len; ++i)
      {
        hash += key[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
      }
      hash += (hash << 3);
      hash ^= (hash >> 11);
      hash += (hash << 15);
      return (hash & mask);
    }