So... all is in code:
// get vector...
SignVector v = ...;
//print to console: [1058, 5, 820 in flat]
System.out.println(v);
//size: 1
System.out.println("size: " + signs.size());
//check all elements...
for (Entry<SignVector, FakeSign> entry : signs.entrySet())
{
// get key
SignVector key = entry.getKey();
//print to console: [1058, 5, 820 in flat] (YaY! it's that key! like v)
System.out.println(key);
if (key.equals(v))
{
// print: "YaY: "
System.out.println("YaY: [1058, 5, 820 in flat]"+key);
}
}
//So second test... just get it from map: null
System.out.println(signs.get(v));
Why that return null?
In JavaDocs is written that: map.get using key.equals(k) so why my code return good object, but map.get return null?
Map:
private final Map<SignVector, FakeSign> signs = new HashMap<>()
Equals method form SignVector for #home user
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SignVector other = (SignVector) obj;
// w can't be null so I skip that
System.out.print(w.getName() + ", " + other.w.getName() + ", " + (w.getName().equals(other.w.getName()))); // this same
if (!w.getName().equals(other.w.getName()))
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
if (z != other.z)
return false;
return true;
}
But this method works good, always return that I want, x,y,z is int, and w is custom object.
The javadoc is a bit misleading, but it's relying on the fact that if you implement equals, you should also implement hashcode to be consistent. As the doc states:
Many methods in Collections Framework interfaces are defined in terms
of the equals method. For example, the specification for the
containsKey(Object key) method says: "returns true if and only if this
map contains a mapping for a key k such that (key==null ? k==null :
key.equals(k))."
This specification should not be construed to imply
that invoking Map.containsKey with a non-null argument key will cause
key.equals(k) to be invoked for any key k.
Implementations are free to
implement optimizations whereby the equals invocation is avoided, for
example, by first comparing the hash codes of the two keys. (The
Object.hashCode() specification guarantees that two objects with
unequal hash codes cannot be equal.)
More generally, implementations
of the various Collections Framework interfaces are free to take
advantage of the specified behavior of underlying Object methods
wherever the implementor deems it appropriate.
Let's take a look a the underlying implementation of get for an HashMap.
314 public V get(Object key) {
315 if (key == null)
316 return getForNullKey();
317 int hash = hash(key.hashCode());
318 for (Entry<K,V> e = table[indexFor(hash, table.length)];
319 e != null;
320 e = e.next) {
321 Object k;
322 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
323 return e.value;
324 }
325 return null;
326 }
You see that is uses the hashcode of the object to find the possible entries in the table and THEN it uses equals to determine which value it has to return. Since the entry is probably null, the for loop is skipped and get returns null.
Override hashCode in your SignVector class to be consistent with equals and everything should work fine.
From the javadocs:
If this map permits null values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.
Unless you share with us how you built the map, we can't help you if this is the case. The code you shared should otherwise be working just fine.
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#get%28java.lang.Object%29
Related
I have a Class Levels which has a hashMap declared.
public class Levels{
private final Map<Unit, Object1> rateUnitCost;
public Levels(Map<Unit, Object1> levels) {
this.rateUnitCost = new HashMap<Unit, Object1>(levels);
}
public Object1 getCoverageLevel(Unit unit, Phase aP) {
return rateUnitCost.get(unit);
}
}
I am calling getCoverageLevel() method from other class and i am instantiating the Levels class rateUnitCost property as well from another class.
When seeing in debugger i am finding this value for rateUnitCost and unit object.
rateUnitCost: - Hash Map Values
rateUnitCost HashMap<K,V> (id=1248)
[0] HashMap$Node<K,V> (id=1266)
key >Unit (id=1249)
amount Money (id=1267)
flags ArrayList<E> (id=1268)
procedureId 7156
ParticipationId 104152413
value >Object1 (id=1250)
Now value of unit object is below :-
unit Unit (id=1251)
amount Money (id=1258)
flags ArrayList<E> (id=1259)
procedureId 7156
ParticipationId 104152413
when i match the value of key with this object then its matching .
But at the time of rateUnitCost.get(unit) its returning null even though Object1 is set. Object1 is getting returned from other class using below line: -
return new Object1();
Can anyone please help me to resolve this mystery.?
BasicUnit is a class which is implementing the Unit interface. BasicUnit have equals method as below :-
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BasicUnit basicUnit = (BasicUnit) o;
if (flags != basicUnit.flags) return false;
if (procedureId != basicUnit.procedureId) return false;
if (ParticipationId != basicUnit.ParticipationId) return false;
if (amount != null ? !amount.equals(basicUnit.amount) : basicUnit.amount != null) return false;
return true;
}
and HashCode :-
public int hashCode() {
int result = procedureId;
result = 31 * result + ParticipationId;
result = 31 * result + (amount != null ? amount.hashCode() : 0);
result = 31 * result + (flags == null ? null : flags.hashCode());
return result;
}
if (flags != basicUnit.flags) return false;
You are checking for whether your Unit objects have exactly the same ArrayList of flags. This is not an equals()-type equality check; this is checking for literally the same ArrayList of flags. Now, you haven't provided the constructor etc, but I highly doubt you are reusing the same ArrayList.
Check for !(flags.equals(basicUnit.flags)) instead. Do note that ArrayList.equals() uses the E.equals() implementation, so be sure that that is implemented.
Also, note that ArrayList.equals() checks for the same list entries in the same order. I don't know if the order of your flags matters but I suspect it probably does not. You might consider making your flag collection a Set if this is the case.
I need to implement equals() and hashCode() for an Address class.
I believe,the non null fields are taken to determine hashCode() and equals().In my application,Any of the fields except addressLine1 and country can be null.If that is the case,what happens if two different addresses have the same addressline1 and country?
Address1:(in state of NH which is omitted by user)
addressline1:111,maple avenue
country: US
Address2:
addressline1:111,maple avenue
state: Illinois
country: US
In such cases if I build a hashCode based only on non null fields ,it will give same for both addresses above.
Is this the right way to create hashCode?
int hash = addressline.hashCode();
if(addressLine2!=null){
hash += addressLine2.hashCode();
}
and so on...
Typically you would check whether one is null and the other is not in your equals method. For hashcode, you would just use 0 as the null hashcode. Example:
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addressLine1 == null) ? 0 : addressLine1.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
result = prime * result + ((country == null) ? 0 : country.hashCode());
return result;
}
If you use an IDE, it will usually generate these for you. In eclipse, choose Source, Generate equals and hashcode and it will let you select the fields you want to be a part of your equals and hashcode methods. For the equals method and your fields, this is what eclipse creates:
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
YourClass other = (YourClass) obj;
if (addressLine1 == null) {
if (other.addressLine1 != null) return false;
} else if (!addressLine1.equals(other.addressLine1)) return false;
if (country == null) {
if (other.country != null) return false;
} else if (!country.equals(other.country)) return false;
if (state == null) {
if (other.state != null) return false;
} else if (!state.equals(other.state)) return false;
return true;
}
I would use that as a starting point and make any changes you think are neccessary from there.
Even fields that are null should be compared for equality. Use code like the following
to compare two fields of nonprimitive types, like String:
this.addressline==null ? other.addressline==null : this.addressline.equals(other.addressline)
For hash codes, use the same fields you used in equals, but you can treat null values as
having a hash code of 0 (or any other hash code value).
Here's the canonical question:
What issues should be considered when overriding equals and hashCode in Java?
And here are discussions of libraries that help you implement these methods properly:
Apache Commons equals/hashCode builder (also discusses Guava)
I have the following situation: I have many BSTs, and I want to merge isomorphic subtrees to save space.
I am hashing Binary Search Tree nodes into a "unique table" - basically a hash of BST nodes.
Nodes that have the same left and right child and the same key have the same hash code, and I have overridden equals for the node class appropriately.
Everything works, except that computing the hash is expensive - it involves computing the hash for the child nodes.
I would like to cache the hashed value for a node. The problem I have is the natural way of doing this, a HashMap from nodes to integers, will itself call the hash function on the nodes.
I've gotten around this by declaring a new field in the nodes, which I use to store the hash code. However, I feel this is not the right solution.
What I really want is to to map nodes to their hash codes using a hash which uses the node's address. I thought I could do this by making HashMap, and casting the nodes to object, which would then invoke the hashCode method on objects, but this didn't work (inserts into the hash still call the node hash and equality functions.
I would appreciate insight into the best way of implementing the node to hash code cache. I've attached code below illustrating what's going on below.
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
class Bst {
int key;
String name;
Bst left;
Bst right;
public Bst( int k, String name, Bst l, Bst r ) {
this.key = k;
this.name = name;
this.left = l;
this.right = r;
}
public String toString() {
String l = "";
String r = "";
if ( left != null ) {
l = left.toString();
}
if ( right != null ) {
r = right.toString();
}
return key + ":" + name + ":" + l + ":" + r;
}
#Override
public boolean equals( Object o ) {
System.out.println("calling Bst's equals");
if ( o == null ) {
return false;
}
if ( !(o instanceof Bst) ) {
return false;
}
Bst n = (Bst) o;
if ( n == null || n.key != key ) {
return false;
} else if ( n.left != null && left == null || n.right != null && right == null ||
n.left == null & left != null || n.right == null && right != null ) {
return false;
} else if ( n.left != null && n.right == null ) {
return n.left.equals( left );
} else if ( n.left != null && n.right != null ) {
return n.left.equals( left ) && n.right.equals( right );
} else if ( n.left == null && n.right != null ) {
return n.right.equals( right );
} else {
return true;
}
}
#Override
public int hashCode() {
// the real hash function is more complex, entails
// calling hashCode on children if they are not null
System.out.println("calling Bst's hashCode");
return key;
}
}
public class Hashing {
static void p(String s) { System.out.println(s); }
public static void main( String [] args ) {
Set<Bst> aSet = new HashSet<Bst>();
Bst a = new Bst(1, "a", null, null );
Bst b = new Bst(2, "b", null, null );
Bst c = new Bst(3, "c", null, null );
Bst d = new Bst(1, "d", null, null );
a.left = b;
a.right = c;
d.left = b;
d.right = c;
aSet.add( a );
if ( aSet.contains( d ) ) {
p("d is a member of aSet");
} else {
p("d is a not member of aSet");
}
if ( a.equals( d ) ) {
p("a and d are equal");
} else {
p("a and d are not equal");
}
// now try casts to objects to avoid calling Bst's HashCode and equals
Set<Object> bSet = new HashSet<Object>();
Object foo = new Bst( a.key, a.name, a.left, a.right );
Object bar = new Bst( a.key, a.name, a.left, a.right );
bSet.add( foo );
p("added foo");
if ( bSet.contains( bar ) ) {
p("bar is a member of bSet");
} else {
p("bar is a not member of bSet");
}
}
}
Storing the hash in a field in the node feels like exactly the right solution to me. It's also what java.lang.String uses for its own hash code. Aside from anything else, it means that you can't possibly end up with cache entries for objects which can otherwise be collected, etc.
If you really want the value of hashCode that would be returned by the implementation in Object, you can use System.identityHashCode though. You shouldn't rely on this - or any other hash code - being unique though.
One other point: your tree is mutable at the moment by virtue of the fields being package access. If you cache the hash code the first time you call it, you won't "notice" if it would have changed due to fields changing. Basically you shouldn't change a node after you've used its hash code.
Java's built-in IdentityHashMap does what you're describing.
That said, Jon Skeet's answer sounds more like the right way to go.
storing the hash in a field can actually be equivalent to "caching" the value so that it does not have to be recomputed too frequently.
It's not necessarily a bad practice, but you have to make sure that you are clearing/recomputing it correctly whenever there is a change, which can be daunting if you have to notify of a change up or down a complex graph or tree.
If you want to use a hash code computed by the JVM (roughly based on the "RAM address" of the object, even if it's value is implementation specific), you can use System.identityHashCode(x), which does exactly that, and exactly what Object.hashCode does.
What I really want is to to map nodes to their hash codes using a hash which uses the node's address.
What do you mean by the node's address? There is no such concept in Java, and there is no unique identifier for objects that I know of, like the physical address in non VM based languages e.g. C++. References in Java are not memory addresses, and objects may be relocated in memory anytime by the GC.
I thought I could do this by making HashMap, and casting the nodes to object, which would then invoke the hashCode method on objects, but this didn't work
Indeed, since hashCode is virtual, and is overridden in your node class, so always the subclass implementation will be called, regardless of the static type of the reference you have.
I am afraid any attempt to use a map to cache hash values bumps into the same chicken and egg problem, that - as you mention - the map needs the hash value itself first.
I don't see any better way than caching the hash values within the nodes as you did. You need to ensure though that the cached values are invalidated whenever the child nodes change. Wrong - as Jon's answer points out, changing the hashcode of an object after it is stored in a map breaks the map's internal integrity, so it must not happen.
I've been encountering some strange behavior when trying to find a key inside a java.util.HashMap, and I guess I'm missing something. The code segment is basically:
HashMap<Key, Value> data = ...
Key k1 = ...
Value v = data.get(k1);
boolean bool1 = data.containsKey(k1);
for (Key k2 : data.keySet()) {
boolean bool2 = k1.equals(k2);
boolean bool3 = k2.equals(k1);
boolean bool4 = k1.hashCode() == k2.hashCode();
break;
}
That strange for loop is there because for a specific execution I happen to know that data contains only one item at this point and it is k1, and indeed bool2, bool3 and bool4 will be evaluated to true in that execution. bool1, however, will be evaluated to false, and v will be null.
Now, this is part of a bigger program - I could not reproduce the error on a smaller sample - but still it seems to me that no matter what the rest of the program does, this behavior should never happen.
EDIT: I have manually verified that the hash code does not change between the time the object was inserted to the map and the time it was queried. I'll keep checking this venue, but is there any other option?
This behavior could happen if the hash code of the key were changed after it was inserted in to the map.
Here's an example with the behavior you described:
public class Key
{
int hashCode = 0;
#Override
public int hashCode() {
return hashCode;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
return hashCode == other.hashCode;
}
public static void main(String[] args) throws Exception {
HashMap<Key, Integer> data = new HashMap<Key, Integer>();
Key k1 = new Key();
data.put(k1, 1);
k1.hashCode = 1;
boolean bool1 = data.containsKey(k1);
for (Key k2 : data.keySet()) {
boolean bool2 = k1.equals(k2);
boolean bool3 = k2.equals(k1);
boolean bool4 = k1.hashCode() == k2.hashCode();
System.out.println("bool1: " + bool1);
System.out.println("bool2: " + bool2);
System.out.println("bool3: " + bool3);
System.out.println("bool4: " + bool4);
break;
}
}
}
From the API description of the Map interface:
Note: great care must be exercised if
mutable objects are used as map keys.
The behavior of a map is not specified
if the value of an object is changed
in a manner that affects equals
comparisons while the object is a key
in the map. A special case of this
prohibition is that it is not
permissible for a map to contain
itself as a key. While it is
permissible for a map to contain
itself as a value, extreme caution is
advised: the equals and hashCode
methods are no longer well defined on
such a map.
Also, there are very specific requirements on the behavior of equals() and hashCode() for types used as Map keys. Failure to follow the rules here will result in all sorts of undefined behavior.
If you're certain the hash code does not change between the time the key is inserted and the time you do the contains check, then there is something seriously wrong somewhere. Are you sure you're using a java.util.HashMap and not a subclass of some sort? Do you know what implementation of the JVM you are using?
Here's the source code for java.util.HashMap.getEntry(Object key) from Sun's 1.6.0_20 JVM:
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
As you can see, it retrieves the hashCode, goes to the corresponding slot in the table, then does an equals check on each element in that slot. If this is the code you're running and the hash code of the key has not changed, then it must be doing an equals check which must be failing.
The next step would be for you to give us some more code or context - the hashCode and equals methods of your Key class at a minimum.
Alternatively, I would recommend hooking up to a debugger if you can. Watch what bucket your key is hashed to, and step through the containsKey check to see where it's failing.
Is this application multi-threaded? If so, another thread could change the data between the data.containsKey(k1) call and the data.keySet() call.
If equals() returns true for two objects, then hashCode() should return the same value. If equals() returns false, then hashCode() should return different values.
For Reference:
http://www.ibm.com/developerworks/java/library/j-jtp05273.html
Perhaps the Key class looks like
Key
{
boolean equals = false ;
public boolean equals ( Object oth )
{
try
{
return ( equals ) ;
}
finally
{
equals = true ;
}
}
}
We are storing a String key in a HashMap that is a concatenation of three String fields and a boolean field. Problem is duplicate keys can be created if the delimiter appears in the field value.
So to get around this, based on advice in another post, I'm planning on creating a key class which will be used as the HashMap key:
class TheKey {
public final String k1;
public final String k2;
public final String k3;
public final boolean k4;
public TheKey(String k1, String k2, String k3, boolean k4) {
this.k1 = k1; this.k2 = k2; this.k3 = k3; this.k4 = k4;
}
public boolean equals(Object o) {
TheKey other = (TheKey) o;
//return true if all four fields are equal
}
public int hashCode() {
return ???;
}
}
My questions are:
What value should be returned from hashCode(). The map will hold a total of about 30 values. Of those 30, there are about 10 distinct values of k1 (some entries share the same k1 value).
To store this key class as the HashMap key, does one only need to override the equals() and hashCode() methods? Is anything else required?
Just hashCode and equals should be fine. The hashCode could look something like this:
public int hashCode() {
int hash = 17;
hash = hash * 31 + k1.hashCode();
hash = hash * 31 + k2.hashCode();
hash = hash * 31 + k3.hashCode();
hash = hash * 31 + k4 ? 0 : 1;
return hash;
}
That's assuming none of the keys can be null, of course. Typically you could use 0 as the "logical" hash code for a null reference in the above equation. Two useful methods for compound equality/hash code which needs to deal with nulls:
public static boolean equals(Object o1, Object o2) {
if (o1 == o2) {
return true;
}
if (o1 == null || o2 == null) {
return false;
}
return o1.equals(o2);
}
public static boolean hashCode(Object o) {
return o == null ? 0 : o.hashCode();
}
Using the latter method in the hash algorithm at the start of this answer, you'd end up with something like:
public int hashCode() {
int hash = 17;
hash = hash * 31 + ObjectUtil.hashCode(k1);
hash = hash * 31 + ObjectUtil.hashCode(k2);
hash = hash * 31 + ObjectUtil.hashCode(k3);
hash = hash * 31 + k4 ? 0 : 1;
return hash;
}
In Eclipse you can generate hashCode and equals by Alt-Shift-S h.
Ask Eclipse 3.5 to create the hashcode and equals methods for you :)
this is how a well-formed equals class with equals ans hashCode should look like: (generated with intellij idea, with null checks enabled)
class TheKey {
public final String k1;
public final String k2;
public final String k3;
public final boolean k4;
public TheKey(String k1, String k2, String k3, boolean k4) {
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
this.k4 = k4;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TheKey theKey = (TheKey) o;
if (k4 != theKey.k4) return false;
if (k1 != null ? !k1.equals(theKey.k1) : theKey.k1 != null) return false;
if (k2 != null ? !k2.equals(theKey.k2) : theKey.k2 != null) return false;
if (k3 != null ? !k3.equals(theKey.k3) : theKey.k3 != null) return false;
return true;
}
#Override
public int hashCode() {
int result = k1 != null ? k1.hashCode() : 0;
result = 31 * result + (k2 != null ? k2.hashCode() : 0);
result = 31 * result + (k3 != null ? k3.hashCode() : 0);
result = 31 * result + (k4 ? 1 : 0);
return result;
}
}
The implementation of your hashCode() doesn't matter much unless you make it super stupid. You could very well just return the sum of all the strings hash codes (truncated to an int) but you should make sure you fix this:
If your hash code implementation is slow, consider caching it in the instance. Depending on how long your key objects stick around and how they are used with the hash table when you get things out of it you may not want to spend longer than necessary calculating the same value over and over again. If you stick with Jon's implementation of hashCode() there is probably no need for it as String already cache its hashCode() for you.
This is however more of a general advice, since the mid 90's I've seen quite a few developers get stung on slow (and even worse, changing) hashCode() implementations.
Don't be sloppy when you create the equals() implementation. Your equals() above will be both ineffective and flawed. First of all you don't need to compare the values if the objects have different hash codes. You should also return false (and not a null pointer exception) if you get a null as the argument.
The rules are simple, this page will walk you through them.
Edit:
I have to ask one more thing... You say "Problem is duplicate keys can be created if the delimiter appears in the field value". Why is that?
If the format is key+delimiter+key+delimiter+key it really doesn't matter if there are one or more delimiters in the keys unless you get really unlucky with a combination of two keys and in that case you probably should have selected another delimiter (there are quite a few to choose from in unicode).
Anyway, Jon is right in his comment below... Don't do caching "until you've proven it's a good thing". It is a good practice always.
Have you taken a look at the specifications of hashCode()? Perhaps this will give you a better idea of what the function should return.
I do not know if this is an option for you but apache commons library provides an implementation for MultiKeyMap
For the hashCode, you could instead use something like
k1.hashCode() ^ k2.hashCode() ^ k3.hashCode() ^ k4.hashCode()
XOR is entropy-preserving, and this incorporates k4's hashCode in a much better way than the previous suggestions. Just having one bit of information from k4 means that if all your composite keys have identical k1, k2, k3 and only differing k4s, your hash codes will all be identical and you'll get a degenerate HashMap.
I thought your main concern was speed (based on your original post)? Why don't you just make sure you use a separator which does not occur in your (handfull of) field values? Then you can just create String key using concatenation and do away with all this 'key-class' hocus pocus. Smells like serious over-engineering to me.