0
public Class myClass{
private final int[][] board;
}

I have

LinkedHashMap<Integer,Object> myMap

where Integer is a hashcode i create by using Arrays.deepHashCode

public int hashCode() {
        int hash = 5;
        hash = 89 * hash + Arrays.deepHashCode(this.board);
        return hash;
    }

public boolean equals(Object anObject) {
        if (anObject == null) return false;
        if (anObject == this) return true;
        if (!(anObject instanceof myClass))return false;

        Puzzle anotherClass = (myClass)anObject;
        return Arrays.deepEquals(this.board,anotherClass.board);
    }

I get new objects and i need to add them to myMap only if they don't exist. I tried to check the hashcode using myMap.containsKey(hashcode) apparently i'm getting duplicate hashcode for different objects.

I tried to check further details when i get true from myMap.containsKey(hashcode) but then i can't add them to myMap as they have the same key!!

Is there any workaround for this problem since using ArrayList and checking with contains() is extremely slow and i have a large number of iterations.

Hazu
  • 105
  • 1
  • 11
  • 4
    You shouldn't be using the `Integer` as the key in the map; you should be using a `Board` object as the key, and that should be the implementation of `Board.hashCode()`. – Louis Wasserman Apr 13 '17 at 16:55
  • 4
    How large will your board be? BTW please don't name the class `Object`. – kennytm Apr 13 '17 at 16:56
  • Why do you need to use a Map anyway? If you just want to have a "List" that does not allow duplicate entries then using a simple Set is the way to go. – OH GOD SPIDERS Apr 13 '17 at 16:58
  • In addition to what Louis said, you should also use a HashSet, not a Map, if all you need to know is if a collection contains a board. – JB Nizet Apr 13 '17 at 16:58
  • Do you only have `board` as an attribute of `myClass`? I mean, in your `equals` method you're only using the `board` attribute. What makes two `myClass` instances different each other? Just the board? Or maybe there exist two `myClass` instances that have equal boards but are still different? – fps Apr 13 '17 at 17:37
  • @JBNizet board is a private attribute (mostly 4*4 array) in myClass which has other attributes and am doing checking outside myClass. – Hazu Apr 13 '17 at 17:49
  • @FedericoPeraltaSchaffner i have other attributes and when implementing equal am interested only in board attribute. So yes there will be two different instances of MyClass which they have equal boards! – Hazu Apr 13 '17 at 17:53

2 Answers2

1

It looks you are missing some key points in here.

First, You are not required to use a hashcode value as a key in your Map.Instead, You have to use the object that implemented the hashcode.

Second, As the part of the contract you have to implement both the hashcode() and equals() methods of the Object class to make sure those classes(like HashMap, HashSet etc..) who depends on those methods work properly

Third, You have to do a little research on how to write a good hash function to minimize the possibility of having two objects the same hashcode value. Look in the below threads

What is a best practice of writing hash function in java?

How to write hashCode method for a particular class?

Community
  • 1
  • 1
Yohannes Gebremariam
  • 2,225
  • 3
  • 17
  • 23
-1

I'm leaving this up temporarily for posterity, but basically the other posters are right, you should be using a HashSet. See the comments below regarding how tricky implementing your own collection classes can be. You have the right idea, but the details are tripping you up.


Wrong, won't work:

I'm going out on a limb here and guess that you didn't implement equals() for your class.

If you implement hashcode() you must also implement equals(), otherwise nothing works. (Or at least a lot of things don't work very well.)

markspace
  • 10,621
  • 3
  • 25
  • 39
  • 2
    The problem is not this. OP is using the hashCode() directly as the key... – kennytm Apr 13 '17 at 16:57
  • Which is basically how a HashSet works, right? It should be possible, even if it's not a great idea. My other concern though is that if he mutates that array he's going to get a different hash code, which is really going to lead to problems. – markspace Apr 13 '17 at 16:58
  • 2
    @markspace no. A HashSet uses the object itself as the key of its internal map. Not the hashCode of the object. If it used the hashCode, the set would reject two objects that have the same hashCode, but that are not equal. – JB Nizet Apr 13 '17 at 17:00
  • @JBNizet But that's what a HashSet does. It uses the "object itself" to call the hash function, the buckets the object in the appropriate location. In a HashMap, no less. It's been a while since I looked at grep code for the HashSet class but I'm pretty sure that's how it works. – markspace Apr 13 '17 at 17:02
  • There is a big difference between a HashMap, which is what a HashSet internally uses, and a HashMap, which is what the OP is using. The first one will happily store two unequal SomeObject instances that have the same hashCode. The second one won't. – JB Nizet Apr 13 '17 at 17:05
  • Yeah true. "Integer" would replace the object or report a collision. OK I was wrong there. – markspace Apr 13 '17 at 17:07
  • 1
    I implemented equal() and i'm gona add it in my question sorry! and the reason i don't use HashSet that i need to maintain the order of the items in my collection. – Hazu Apr 13 '17 at 17:08
  • 2
    @Hazu so use LinkedHashSet. – JB Nizet Apr 13 '17 at 17:10