【问题标题】:Different Enum HashCode generation?不同的 Enum HashCode 生成?
【发布时间】:2012-02-24 18:18:12
【问题描述】:

为什么每次运行 java main 都有不同的 hashCode 值? 请看下面的示例代码。

interface testInt{

    public int getValue();
}

enum test  implements testInt{
    A( 1 ),
    B( 2 );

    private int value;

    private test( int value ) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}

每次跑步,

public static void main( String[] args ) {
     System.out.println( test.A.hashCode() );
}

控制台上会有不同的打印值。 为什么会出现这种不一致?

【问题讨论】:

    标签: java interface enums hashcode


    【解决方案1】:

    如果您每次都想要相同的值,请使用.ordinal() 或者更好,请像您一样使用getValue()。您可以从默认值中覆盖 hashCode(),即根据对象的创建方式给它一个数字。

    【讨论】:

    • 是的,我现在使用 getValue 作为解决方案。刚刚创建了这篇文章,以了解实现接口时为什么会有不同的 hashCode。谢谢。
    【解决方案2】:

    “不要求哈希值在不同的 Java 实现之间保持一致,甚至在同一程序的不同执行运行之间。”

    http://en.wikipedia.org/wiki/Java_hashCode%28%29

    http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#hashCode%28%29

    public static void main( String[] args ) {
         System.out.println( test.A.hashCode() );
         System.out.println( test.A.hashCode() );
    }
    

    此代码现在将产生相同的 hashCode。

    【讨论】:

    • 好的,但是,只有当你有一个实现接口的枚举时才会发生这种情况。
    • 不一定。如果您要比较的是在程序执行之间生成字符串(或其他内容)的哈希码,那么它们生成相同代码的事实可能是巧合。
    • 我想巧合在这里不是正确的词。它确实为未实现任何接口的枚举返回相同的 hashCode 值。这就是我指向这里的原因。
    【解决方案3】:

    javadocs 清楚地说明了这一点。来自对象 c 中哈希码方法的 javadocs 类

    在合理的情况下,Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)

    因此,在演示代码的不同运行中,内部地址可能会有所不同,因此您看到不同的值是完全正常的。

    根据您的需要,如果您希望 hashcode() 方法在 jvm 调用中返回相同的值,您应该重写该方法以返回自定义值。但是,您应该知道,如果要在基于散列的集合中使用对象,这可能是灾难性的(散列冲突的机会增加)。

    【讨论】:

    • 如我所说。把我带到这里的是一个事实,在我的 Oracle JVM7 中,简单的枚举在不同的运行中返回相同的 hashCode。但是当换成专门的枚举时,每次运行的哈希码都是不同的。
    【解决方案4】:

    也许一些 JVM 实现基本上会返回 Enum.ordinal()(这也将是很好的 hashCode) - 但它不会有效地改变任何东西。 hashCode() 值不必在执行或 JVM 之间保持一致。唯一需要的合同在Object.hashCode() 的JavaDocs 中描述 - 它是在Object 中的实现,在enum 中使用。

    还要注意,实现接口与hashCode()无关:

    public class TestEnum {
    
        public static void main(String[] args) {
            System.out.println(Silly.B.hashCode());
            System.out.println(Silly.C.hashCode());
            System.out.println(Silly.D.hashCode());
        }
    }
    
    enum Silly {
        B, C, D
    }
    

    这个程序在每次运行时也会返回不同的hashCode()s。

    【讨论】:

    • 好吧,Silly.B.hashCode,将返回相同而不是不同的 hasCode。如果实现一个接口与 hashCode 无关,为什么会发生这种情况?你知道我要去哪里吗? Silly.B.hashCode 在不同的运行中是相等的,但是如果你让 Silly 实现一个简单的接口,那么 Silly.A 会有不同的 hashCodes
    • @VíctorHugo:您使用的是哪个 JVM?在 1.6.0_26-b03 上,它有时会返回相同的值,有时会返回不同的值,但可以肯定的是它们并不总是相同...
    【解决方案5】:

    Enum.hashCode 没有被定义为返回任何特定的值(除了遵守Object.hashCode 的规则),常见的实现没有做任何特殊的事情。

    为什么?如果您在HashSet 中使用枚举(仅)或作为HashMap 中的键,那么您应该使用优化的EnumSetEnumMap。现在考虑枚举是否要与HashSet 中的其他类型一起使用。也许您有一些“标准选项”来实现接口,但其他人可以提供自己的选项。任何无国籍的事情都会做。多个枚举类型在一个 HashSet 中。如果Enum 使用序数作为哈希值,那么您将遇到常见的冲突。使用System.identityHashCode 可以稳健地减少冲突。

    public interface Option {
    }
    public enum StandardOptions implements Option {
        A, B, C
    }
    enum CustomOptions {
        P, Q, R
    }
    enum MoreOptions {
        X, Y, Z
    }
    
        Set<Option> options = new HashSet<>();
        options.add(A);
        options.add(P);
        options.add(X);
    

    我们真的不想要A.hashCode() == P.hashCode() == X.hashCode()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多