Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java hashCode可以在不同的运行之间返回不同的值吗?_Java_Hash_Non Deterministic - Fatal编程技术网

Java hashCode可以在不同的运行之间返回不同的值吗?

Java hashCode可以在不同的运行之间返回不同的值吗?,java,hash,non-deterministic,Java,Hash,Non Deterministic,我正在努力学习hashCode背后的完整故事。在大多数实现中,hashCode是完全确定的,如在StringUTF16类中: public static int hashCode(byte[] value) { int h = 0; int length = value.length >> 1; for (int i = 0; i < length; i++) { h = 31 * h + getChar(value, i); }

我正在努力学习
hashCode
背后的完整故事。在大多数实现中,
hashCode
是完全确定的,如在
StringUTF16
类中:

public static int hashCode(byte[] value) {
    int h = 0;
    int length = value.length >> 1;
    for (int i = 0; i < length; i++) {
        h = 31 * h + getChar(value, i);
    }
    return h;
}

现在,我的问题是:这个实现有什么不好的地方吗?我能看到的唯一问题是,它将为不同的程序运行返回不同的哈希代码,但我无法想象会出现错误的具体场景。

除非您进入序列化的专门应用程序,否则我看不出有什么问题。在大多数情况下,就运行时而言,设置它的方式基本上相当于添加任意的
31
值(该值不变)

不过,通过反射“诡计”,您可能会改变值并使整个系统偏离轨道(想想
setAccessible
和修改器标志)


当对象被序列化并传输到不同的环境时,如果存在依赖于哈希代码和一致性的设置,我认为出现问题的可能性更大。两个独立环境之间的哈希代码比较方式很可能会有所不同,但实际上它们不应该有所不同。

除非您进入序列化的专门应用程序,否则我不认为这是一个很大的问题。在大多数情况下,就运行时而言,设置它的方式基本上相当于添加任意的
31
值(该值不变)

不过,通过反射“诡计”,您可能会改变值并使整个系统偏离轨道(想想
setAccessible
和修改器标志)


当对象被序列化并传输到不同的环境时,如果存在依赖于哈希代码和一致性的设置,我认为出现问题的可能性更大。两个独立环境之间的哈希代码比较方式很可能会有所不同,但实际上它们不应该如此。

不要求
hashCode
在不同JVM中给出相同的值。例如,序列化映射时,
HashMap
类不会持久化映射键的
hashCode
值。相反,反序列化映射时会重新计算
hashCode

我能看到的唯一潜在问题是在每次调用时重新计算
hashCode
,效率低下。您可以通过延迟计算来解决这个问题(例如,
String::hashCode
does)

但是如果实现了lazy
hashCode
计算,则需要将存储它的字段声明为
transient
。否则,取消持久化密钥实例中的
hashCode
值将不会
=
为另一个与该密钥“相等”的实例计算的
hashCode
值。(换句话说,hashcode/equals契约被破坏!)这将导致查找失败

如果正确地执行此操作,那么对
HashMap
的序列化应该不会有问题。例如,您可以遵循
String::hashCode
的方法,使用零作为
hashCode
方法的缓存
hashCode
值,这意味着“需要计算代码”

(如果您的密钥类没有用于保存缓存的
hashCode
值的字段,则不会出现持久化该值的问题。)



另一件需要注意的事情是,修改key类以实现
Comparable
将是另一种防御基于DOS的攻击的方法。在示例类中,
compareTo
方法的实现非常简单。请注意,您实现的顺序不需要在语义上有意义。它只需要稳定和一致。

不要求
hashCode
在不同的JVM中提供相同的值。例如,序列化映射时,
HashMap
类不会持久化映射键的
hashCode
值。相反,反序列化映射时会重新计算
hashCode

我能看到的唯一潜在问题是在每次调用时重新计算
hashCode
,效率低下。您可以通过延迟计算来解决这个问题(例如,
String::hashCode
does)

但是如果实现了lazy
hashCode
计算,则需要将存储它的字段声明为
transient
。否则,取消持久化密钥实例中的
hashCode
值将不会
=
为另一个与该密钥“相等”的实例计算的
hashCode
值。(换句话说,hashcode/equals契约被破坏!)这将导致查找失败

如果正确地执行此操作,那么对
HashMap
的序列化应该不会有问题。例如,您可以遵循
String::hashCode
的方法,使用零作为
hashCode
方法的缓存
hashCode
值,这意味着“需要计算代码”

(如果您的密钥类没有用于保存缓存的
hashCode
值的字段,则不会出现持久化该值的问题。)



另一件需要注意的事情是,修改key类以实现
Comparable
将是另一种防御基于DOS的攻击的方法。在示例类中,
compareTo
方法的实现非常简单。请注意,您实现的顺序不需要在语义上有意义。它只需要稳定和一致。

考虑基于哈希的
Map
<代码>哈希映射s将永远无法工作。还有,当
散列的主要目的是存储和检索而不是一个目的时,您如何计划发起攻击wayness@Ryotsu,你说的是某种持久的
映射吗?在这种情况下,hashCode应该是b
class ImmutableArray{
    // Note static keyword. It guarantees that for the same run all objects use the same x.
    private static final int x = generateRandomPrime();

    int[] values;

    public int hashCode() {
        int res = 5;
        for (int v : values) {
            res = res * x + v;
        }
        return res;
    }

    ...

}