Java中空对象的哈希码必须是什么?

14
根据这篇文章中的评论,null对象hashcode可能会抛出NPE或者返回0。这是与实现相关的,但在同一实现中,为什么Objects.hashcodehascode(instance)返回不同的值,例如:
public class EqualsTesting {

    public static void main(String[] args){
        String p1 =null;
        String p2 = null;
        System.out.println(Objects.hashCode(p1));
        System.out.println(p2.hashCode());

    }
}

输出:

0
Exception in thread "main" java.lang.NullPointerException
    at BinaryTrees.EqualsTesting.main(EqualsTesting.java:14)

如果是这种情况,那么这不会影响允许null Key-value pairsHashMap中的key look-up吗?(它可能会hashbucket 0,或者throw a NPE


第一个是静态方法,第二个是非静态的。 - Anirban Nag 'tintinmj'
@tintinmj:那么它们为什么应该返回不同的值呢? - eagertoLearn
4
在Java语言中,不能在null对象上调用hashCode()或者其他任何方法。 - SLaks
3
对于一个null引用,你不能调用任何实例方法。这不仅适用于hashCode()方法。 - Peter Lawrey
根据这篇帖子中的一条评论......我建议您不要在一行评论中读太多,而是阅读真正的答案。 - Stephen C
6个回答

24
当一个对象并不存在时,你如何计算它的hashCode?当p2为null时,在其上调用任何方法都会抛出NPE,这不会给你任何特定的hashCode值。
Objects.hashCode()是一个包装方法,它对null值进行预检查,对于非null的引用,它返回与p2.hashCode()相同的值。在这种情况下,以下是该方法的源代码:
public static int hashCode(Object o) {
    return o != null ? o.hashCode() : 0;
}

1
那么HashMap是否使用Objects.hasCode()来计算null的哈希值呢? - eagertoLearn
那么这些静态的Objects.hashCode()到底有什么用处呢? - eagertoLearn
如果您不想在获取hashCode之前明确检查null,可以使用@eagertoLearn。 - Sanjay T. Sharma
1
@eagertoLearn 如果你想知道数据结构是如何实现的,你可以随时查看其源代码。源代码与你安装的jdk一同分发。 - Rohit Jain
1
HashMap在Objects辅助类之前编写的。如果当时有ObjectsHashMap可能会使用它。 - yshavit
显示剩余3条评论

6
如果你仔细寻找,就会发现 HashMapnull 键有一个特殊处理。由于在 HashMap 中不会为 null 值计算哈希值,因此它们是可以使用的。这也是为什么 null 键可以正常工作的原因。至于为什么 Objects.hashCode 也能正常工作,请参考 Rohit 的答案。

在HashMap的put()方法中,还进行了@sanjay的null检查。如果为null,则从put()方法中调用一个单独的方法。 - rolling stone

3
根据 javadoc 所说:

Objects.hashCode(Object o)

返回非空参数的哈希码,对于空参数返回0。

p2.hashCode() 抛出 NullPointerException 是因为你试图访问null对象的方法。

3
根据此帖子的评论,null对象的哈希码可能会抛出NPE或零值。
这是不正确的。(@Bohemian的评论也不是在说这个!)
在HashMap和HashSet中发生的情况是它们将null视为特殊情况。它们不会调用空对象的hashcode()方法(会导致NPE!!),而是使用零作为硬编码替代哈希码。
我强调...这是HashMap和HashSet的特殊行为...并非hashcode()。
如您的示例所示,如果您尝试调用null上的哈希码()方法,则会收到NPE。 JLS说这就是会发生的事情...无论何时您尝试在null上调用任何实例方法时都会发生。
(另一方面,Objects.hashCode(obj)方法确实处理了当obj为null时的特殊情况。这就是静态方法的全部意义!)

那么为什么像Bohemian所评论的那样,它是实现特定的呢? - eagertoLearn
如何处理此问题取决于您正在实现的内容。在 HashMap / HashSet 的情况下,使用哪个值作为 null 对象的替代哈希值也是实现特定的。但是,为了满足 javadoc 的要求,HashMapHashSet 的实现不能允许在 null 情况下将 NPE 传递到用户代码中。 - Stephen C

0

在 Hashmap 中,0 是硬编码值,代表 null。你可以看到以下实际实现是如何完成的,在 HashMap 和 Objects Java 类中。

来自 HashMap.java

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

来自Object.java

public static int hashCode(Object o) {
        return o != null ? o.hashCode() : 0;
    }

0

null的哈希码为0(参见Objects.hash()

    public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接