2

I was just writing code, and suddenly I came across this warning in Netbeans:

hashCode() called on array instance

It occurred in this piece of code:

public class SomeObject {

    private String a;
    private char[] b;

    @Override
    public boolean equals(Object anotherObject) {
        if (!(anotherObject instanceof SomeObject)) {
            return false;
        }
        SomeObject object = (SomeObject) anotherObject;
        return (this.a.equals(object.a) && arraysAreEqual(this.b, object.b));
    }

    // When I created the equals() method, Netbeans warned me:
    // 'Generate missing hashCode()'. Okay then, here it comes:

    @Override
    public int hashCode() {
        return (43 * this.a.hashCode() + 11 * this.b.hashCode()); // MARKED LINE.
    }
}

The warning occurs on the marked line. The IDE finds that I should avoid calling hashCode() on an array instance.

Now why should I avoid using hashCode() on an array?

Notice that I read this question and answer, but they didn't mention this.

Community
  • 1
  • 1
MC Emperor
  • 22,334
  • 15
  • 80
  • 130

4 Answers4

2

I would better use:

java.utils.Arrays.hashCode(char[] a)

http://www.tutorialspoint.com/java/util/arrays_hashcode_char.htm

In your way you're not testing the contents of the char array.

The java.util.Arrays.hashCode(char[]) method returns a hash code based on the contents of the specified array. For any two char arrays a and b such that Arrays.equals(a, b), it is also the case that Arrays.hashCode(a) == Arrays.hashCode(b).

public void testHashCode() {

    char[] b = { 'a', 'b' };
    char[] a = { 'a', 'b' };
    System.out.println("HashCode b:" + b.hashCode() + " a:" + a.hashCode());
    System.out.println("Array hashCode a:" + java.util.Arrays.hashCode(a) + " b:" + java.util.Arrays.hashCode(b));
}

Result:

HashCode b:8995841 a:8995844
Array hashCode a:4066 b:4066

Hope this helps!

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
akakike
  • 23
  • 6
2

Java arrays are directly derived from java.lang.Object and thus inherit the methods equals and hashCode from it.

The default equals method compares object identity (i.e. whether two references refer to the same object), and the default hashCode method will most probably return different values for different objects.

In most cases, this is a behavior that you do not want. You most probably want to compare arrays based on the content. Note, that your equals method seems to do that, which in turn means that your hashCode method is broken. Look at the method's documentation for the reason.

Java provides a class with helper methods for exactly that reason: java.util.Arrays. It provides the methods equals and hashCode that are both based on the content of the array.

So you should write it like that:

public class SomeObject {

    private String a;
    private char[] b;

    @Override
    public boolean equals(Object anotherObject) {
        if (!(anotherObject instanceof SomeObject)) {
            return false;
        }
        SomeObject object = (SomeObject) anotherObject;
        return (this.a.equals(object.a) && Arrays.equals(this.b, object.b));
    }

    @Override
    public int hashCode() {
        return (43 * this.a.hashCode() + 11 * Arrays.hashCode(this.b));
    }
}
Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
0

The problem is that you can't override an array and it is using the default hashCode() implementation which can cause problems. You can consider this as a design oversight. You should either wrap your arrays in an arbitrary object or don't use hashCode() altogether in the context of arrays.

Adam Arold
  • 29,285
  • 22
  • 112
  • 207
0

The hashCode implementation for arrays is based on the identity of the array and not on the content. In most cases, this is not what you want, since two arrays with identical content will in general have different hash codes.

To base the hash code on the contents of the array you can use the java.utils.Arrays.hashCode method.

Henry
  • 42,982
  • 7
  • 68
  • 84