guava-libraries:Objects.hashCode(Object [])碰撞是否安全?

Joh*_*thy 7 java hashcode guava

在查看覆盖的不同选项时hashCode(),我被引导到Objects.hashCode(Object[])Google的guava-libraries(javadoc)中.javadoc表示它委托给Arrays.hashCode(Object[]).在许多不同的对象类型中使用此方法是否安全?这不容易发生哈希冲突,或者这不仅仅是因为容器通常只包含一种类型的对象?

举个简单的例子,考虑以下类,

public class Student {
    private final String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }
}

public class Teacher {
    private final String name;

    public Teacher(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }
}

public class HashCodeDriver {
    public static void main(String[] args) {
        final String name = "moe";
        Student s = new Student(name);
        Teacher t = new Teacher(name);

        long studentHash = s.hashCode();
        long teacherHash = t.hashCode();
        System.out.println("studentHash=" + studentHash + " teacherHash=" + teacherHash);
        if(studentHash == teacherHash) {
            System.out.println("hash codes match");
        }
        else {
            System.out.println("hash codes don't match");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

studentHash=108322 teacherHash=108322
hash codes match
Run Code Online (Sandbox Code Playgroud)

对象是两种不同的类型,但生成相同的哈希码.这不是问题吗?我应该将类作为第一个参数传入以防止此冲突吗?例如,

public class Student {
    private final String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(Student.class, name);
    }
}

public class Teacher {
    private final String name;

    public Teacher(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(Teacher.class, name);
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是javadoc警告只为这个方法提供单个对象的原因吗?来自javadoc,

警告:提供单个对象时,返回的哈希码不等于该对象的哈希码.

Ale*_*yak 6

当2种不同类型的2个不同对象具有相同的哈希码时,这不是问题.

希望,当你打算建立自己的时候,HashMap你不会把学生和教师作为该地图的关键.即使在你想做的情况下,HashMap<Object, Object>你也会没事,因为

assertFalse( new Teacher( "John Smith" ).equals( new Student( "John Smith" ) );
Run Code Online (Sandbox Code Playgroud)

这就是为什么它同时重写是很重要的hashCodeequals.

委托的唯一缺点Arrays.hashCode(Object[])可能是,从性能的角度来看,有时可能太昂贵.

例如,在您的情况下,对于教师或学生来说,这将是一个更好的哈希方法.

@Override
public int hashCode() {
    return name.hashCode();
}
Run Code Online (Sandbox Code Playgroud)

  • @ nondescript1 - 关于你的陈述"从我看到的,HashMap只使用hashCode,而不是等于">你如何得出这个结论?你能指出我的doc/spec链接吗?根据我的理解,HashSet将使用hashcode值将对象存储在散列桶中,但会在其上调用equals来比较相等性.因此,如果您的教师和学生返回相同的哈希码,他们将被放置在同一个桶中,但如果您想从Map获取教师,它将检查等于然后将返回给您有效的教师或null,因此不会有任何碰撞. (3认同)
  • @ nondescript1 - 我猜你误解了equals和hashcode合约 - 当你重写equals时你必须覆盖hashcode,而两个相等的对象应该产生相同的hashcode,但反之亦然.Object#hashcode的一般契约说 - 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要**,那么在两个对象中的每一个上调用hashCode方法必须产生不同的整数结果.但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能. (2认同)