Results 1 to 20 of 21
Thread: hashCode idea
- 08-14-2011, 03:11 AM #1
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
hashCode idea
Hi,
I was reading about the need to implement both equals() and hashCode() at
Java theory and practice: Hashing it out
and so I want to ask what y'all think of this hashCode() idea. I am looking at an object with 25 data members that I have coded an equals() for, and frankly, unique hashCodes in an int don't seem possible.
How about providing a hashCode int in a given class, also with a static class member which is how high the numbering has gone?
And then add to that the ability to put 20 variables into a single String and perform string comparisons instead of using an int?
Java Code:class foo { static int nextHashIndex = 1; private int hashCode = 0; private String hashString = null; public int hashCode() { if(hashCode == 0) setHashCode(); return hashCode; } public String hashString() { if(hashString == null) setHashCode(); return hashString; } private static int getNextHashIndex() { return nextHashIndex++; } private void setHashCode() { hashCode = getNextHashIndex(); hashString = "convoluted method for putting the hashString together"; } public boolean equals(Object o) { if(hashCode == 0) setHashCode(); return o.hashString().equals(hashString); } }
Would you think this a good approach to dealing with equals, hashCode and compare? For compare, it would be string compare, and one would start with most significant data members to least, I suppose, in building the hashString.
TIA, and cheers,
Mark
-
Sorry but that seems a bad idea. The hashCode should vary as equals varies. If two objects are equal via your equals method, then they must return the same hashCode (the converse is not necessarily true).
- 08-14-2011, 03:20 AM #3
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
Sorry, that was the first stream of consciousness.
The hashString has to be looked up in existing hash strings, which would have to be kept, returning the hash code for the matching string or a new hash code, so hash code comparisons would work (without strings).
Other question: If equals() works OK, and I do not call hashCode(), do I need to implement hashCode()?
TIA, and cheers,
MarkLast edited by Markgm; 08-14-2011 at 03:30 AM.
- 08-14-2011, 03:29 AM #4
It depends on how you are using the classes. If you don't need other classes to hold and sort your class, then it doesn't matter. If you are using the collection framework classes then you need to follow the rules.
- 08-14-2011, 03:42 AM #5
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
Hi,
Here is the way it would work using unique hashCodes for up to a couple billion instances of a class with a complex set of data elements.
There is no provision here for removing strings from the static ArrayList such as when objects are destroyed, which would make it more complete.
Java Code:class foo { private static int nextHashIndex = 1; private static ArrayList<String> hashStrings = new ArrayList<String>(); private int hashCode = 0; private String hashString = null; private static int getHashCode(String s) { int h = hashStrings.indexOf(s); if(h == 0) { hashStrings.add(s); h = nextHashIndex++; } return h; } public int hashCode() { if(hashCode == 0) hashCode = getHashCode(hashString()); return hashCode; } private String hashString() { if(hashString == null) { // create complex hash string } return hashString; } }
- 08-14-2011, 03:44 AM #6
As long as:
If two objects are equal via your equals method, then they must return the same hashCode
- 08-14-2011, 03:54 AM #7
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
Well, if I don't override hashCode(), but I do override equals(), and I think that if my equals() says equal, then the contents of the two will be the same. I believe that will cause any underlying hashCode() call to return equal hash codes?
I am also just realizing, when the foo type above - when the object changes, it will have to do its hash string and code anew. But that is the basic idea - to use an int as an index into a more complete hash code.Last edited by Markgm; 08-14-2011 at 03:56 AM.
- 08-14-2011, 04:05 AM #8
Make a test class, create some instances and put them into a HashMap and see what happens.
Do you understand how hash values are used? The collection uses the hash code to select which bucket to put an object in. A bucket can contain more than one object. Its a way of mapping large index to a smaller space.
For example say your index can have 100 million different values(0-100000000), but your data has only 10 thousand different values with indexes randomly spaced in that 100 million range. You want a way to store those 10 thousand values in an 1000 lists of 10 items each. When you want to retrieve an item using its index in the 100 million range, you need a way to convert it to an index in the 1000 range to select one of the 1000 lists to search for the item using the equals method. If the hash is the same, then you have a list of 10 to search.
The mapping of the index from 100 million to 10 thousand is done by hashing.
Given this, can you see why hash and equals must give correlating values.
- 08-14-2011, 04:16 AM #9
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
I do not know how hashCodes are used by the Object class, for example, which is what I am inheriting from. I have a class with a need to compare using equals(), and over 20 member variables are being compared in it. I'm not sure how well I could make a useful representation of that in a hashCode, or what it would be used for.
Add: These are the members. 3 strings, 11 booleans, 1 short[5-10] boolean array, 5 ints, and 3 mutable refs (each contains 1 boolean, 2 enums and 2 ints).Last edited by Markgm; 08-14-2011 at 04:38 AM.
- 08-14-2011, 04:34 AM #10what it would be used for
- 08-14-2011, 04:44 AM #11
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
If I said that the hash codes I make were relatively meaningless, but always met the requirement that equal value gives an equal hash code, would that meet all of the necessary requirements?
- 08-14-2011, 04:48 AM #12
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
- 08-14-2011, 04:50 AM #13
If two objects are equal with your method and by your hashcode method they will have the same hashcode.
That should work. The classes that use hashcode to select a bucket for an object would be looking in the correct bucket where it could expect to get an equal match. There would be no other buckets where there would be an object that would be equal to the object being placed/searched for.
- 08-14-2011, 04:51 AM #14
What containers are you putting your MyClass objects in?
- 08-14-2011, 05:02 AM #15
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
- 08-14-2011, 05:22 AM #16
By container I was referring to ArrayList, Map, List, Set, etc. A class the you add your MyClass objects to.
They are the classes that will require the equals and hashcode methods to return the right values.
- 08-14-2011, 06:08 AM #17
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
OK. I like to use ArrayList in many places, but I have no look-up kind of activity going on in any container of my objects. The only calls to equals() I am considering are for if there has been a change in one of 20+ different settings while the user is interacting with a view to those (model) settings. So I need an equals() that gives a very precise response of equals or not between current and previous instances of the whole content.
- 08-14-2011, 06:34 AM #18
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
From discussion
java - Should mutable collections override equals and hashCode? - Stack Overflow
You should not override equals and hashCode so that they reflect the mutable member.
There are two reasons:
first: because this would break the contract of hash code:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer...
second: technical vs. business logic
If you break that requirement HashSet and HashMap and every component based on them will probaly not work correct.
The second reason not to do this: is more my personal point of view. I think hash code and equals are technical terms that should not be used to implement business logic. Imagine: you have two Objects (not only Collections) and ask if they are equals, then there are two different ways to answer them:
technical: the are equals if they represent the same object, which is different from being the same object (if you think of proxies, serilization, remote stuff...)
bussines logic: they are equals if the look the same (same attribute) – the important thing here is, that there is not the holy one definition of equality even to the same class in even one application. (Sample question: when are two stones equals?))
But because equals is used by technical stuff (HashMap), you should implement it in a technical way, and build the business logic related equals by something else (something like the comparator interface). And for your collection it means: do not override equals and hashCode (in a way that breaks the technical contract).
- Mark
- 08-14-2011, 10:14 AM #19
Member
- Join Date
- Nov 2010
- Location
- VT, USA
- Posts
- 31
- Rep Power
- 0
Java Code:// the Str class public class Str { private String s = null; public Str(String t) { s = t; } public String string() { return s; } public void setString(String t) { s = t; } public boolean equals(Object o) { Str str = (Str) o; if(str == this) { System.out.println("Str.equals() str == this"); return true; } if(str.string() == this.s) { System.out.println("Str.equals() str.string() == this.s"); return true; } return false; } } // ------------------------------------------------------ // goof - snippet from main() String s = "hello", t = "hello"; if(s == t) System.out.println("s == t"); if(s.equals(t)) System.out.println("s.equals(t)"); Str s1 = new Str("hello"); Str s2 = new Str("hello"); if(s1 == s2) System.out.println("s1 == s2"); if(s1.equals(s2)) System.out.println("s1.equals(s2)"); if(s1.equals(s1)) System.out.println("s1.equals(s1)"); Object o1 = new Object(), o2 = new Object(); if(o1 == o2) System.out.println("o1 == o2"); if(o1.equals(o2)) System.out.println("o1.equals(o2)"); System.out.println("o1 hash: "+o1.hashCode()+", o2 hash: "+o2.hashCode());
Java Code:Output: s == t s.equals(t) Str.equals() str.string() == this.s s1.equals(s2) Str.equals() str == this s1.equals(s1) o1 hash: 1140995926, o2 hash: 1837044219
From Object (Java Platform SE 6)
Under hashCode:
The general contract of hashCode is: ...
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. ...
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. ...
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables. ...
Under equals:
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Perhaps I am now also seeing how these two have to be used. A person must do both (to do one) to maintain all of the contracts. If one overrides equals(), then one really needs to override hashCode() so that they are in synch with each other (and can maintain the above contracts). Although, if I understand how equals() is described above, it uses the reference itself (x or y) as part of what has to be equals? So in class Object, the hashCode is basically the object address, which is a part of being "totally equals". That is too equals for me. I want to have two separate objects that can come out true on equals, by having the same content. So, the basic type Object is only equals if it has the same address, i.e. hashCode. Inheriting from Object, which everything does, can add its own checks for the data members it adds. Or, perhaps in one's equals() implementations, one could skip the basic address hashCoding of Object and just do the derived content, for both the hashCode() and the equals().
Looking at the fine print, the hashCode() can change during execution, when the data used in making the hashCode changes, so the hash code does not have to stay the same during its lifetime. I can always generate hash codes and results for equals() as the current time, so long as they are on the same page with each other (and the contracts above). I might get a performance improvement from more unique hash codes. I do not see a negative to having a hash code that changes however many times during an object's lifetime (beyond the processing required to generate the code).
Other than that, I suppose hashCode() and equals() may get ugly with inheritance... Having to use base class members but add to them. If I make class Derived from class Base, (where I suppose Base is derived from Object), how do I call into the Base equals() and hashCode() from the derived ones?Last edited by Markgm; 08-14-2011 at 12:05 PM.
- 08-14-2011, 02:02 PM #20
Similar Threads
-
Hashcode definition question!!
By chathura87 in forum New To JavaReplies: 8Last Post: 03-03-2011, 04:28 PM -
equals() and HashCode()
By jomypgeorge in forum New To JavaReplies: 1Last Post: 02-10-2011, 08:34 AM -
hashCode() contract
By jomypgeorge in forum New To JavaReplies: 3Last Post: 01-14-2011, 12:32 PM -
hashCode questions
By alpdog14 in forum New To JavaReplies: 3Last Post: 02-20-2010, 12:00 AM -
An acceptable hashcode?
By dsym@comcast.net in forum New To JavaReplies: 7Last Post: 03-29-2009, 10:04 PM
Bookmarks