Hash algorithm-depth understanding of the principles and HashCode

The Java Collection there are two types, one is List, one is Set. Elements within the List is ordered, the element can be repeated. Set disorderly elements, but the elements can not be repeated. To ensure the element does not repeat, repeat if the two elements should be judged according to what it? By Object.equals method. But if each additional element to check once, when a lot of elements, after adding to the number of elements in a set of relatively very much. In other words, if the collection has 1000 elements, then the first 1001 elements to the collection, it is necessary to call the equals method 1000. This obviously will greatly reduce efficiency. So Java uses the principle of the hash table.
When Set receiving element is calculated based on the memory address of the object hashCode, to see if it belongs to which interval, and then call in this interval equeals method. [Special Note] It should be noted that: when the same hashCode value when the two objects, Hashset objects will be stored in the same location, but they are equals returns false, so in fact this position using chain structure to save more object.
      
The above method does improve efficiency. But faced with a problem: if two objects equals are equal, but not in a range, because the value of hashCode is calculated before overwriting memory address, so there is no opportunity to compare, would be considered different objects. So Java for eqauls and hashCode methods is such a requirement:
1 if the two objects are the same, then their hashCode values must be the same. Also tells us rewrite the equals method, be sure to override the hashCode method, which means that hashCode value to member variables and class linked to that, the same objects -> same member variables -> hashCode value necessarily the same.
2 hashCode if two identical objects, they are not necessarily the same, the object here refers to the same method eqauls comparison.

? Then the content is reproduced from: http: //blog.csdn.net/jiangwei0910410003/article/details/22739953 blog ************************ *********************************************

The following look at a concrete example: RectObject objects:

package com.weijia.demo;

public class RectObject {
public int x;
public int y;
public RectObject(int x,int y){
this.x = x;
this.y = y;
}
@Override
public int hashCode(){
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
final RectObject other = (RectObject)obj;
if(x != other.x){
return false;
}
IF (Y = other.y!) {
Return to false;
}
return to true;
}
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
30
31 is
32
33 is
34 is
35
we rewrite the parent class object equals and hashCode method, equals and hashCode method to see if the two RectObject objects x, y values are equal if their values are equal hashCode, equals returns while It is true;
the following are the test code:
Package com.weijia.demo;
java.util.HashSet with Import;
public class Demo {
public static void main (String [] args) {
SET = new new HashSet HashSet <RectObject> <RectObject> ();
RectObject new new RectObject R1 = (3,3);
RectObject R2 = RectObject new new (5, 5);
RectObject new new RectObject R3 = (3,3);
set.add (R1);
set.add (R2);
set.add (R3);
set.add (R1);
the System.out .println ( "size:" + set.size ());
}
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
we deposited to four objects to the HashSet, set print size of the collection, the result how much is it? Operating results: size: 2
2 Why is it? This is very simple, because we override hashCode method RectObject class, as long as x RectObject object, y attribute values ​​are equal then his hashCode values ​​are equal, so the first comparison hashCode value, x r1 and r2 objects, y attribute values ​​ranging hashCode so they are not the same, so r2 object can be put to, but x r3 object, the same property values ​​and property values ​​y r1 object, so hashCode are equal, this time in comparison r1 and the equals method r3, because he it two of x, y values ​​are equal, so r1, r3 objects are equal, so r3 can not go into the same and finally add a r1 is there is no added to it, so set only one set of these two objects r1 and r2

Here we hashCode method RectObject object comments that do not override hashCode method in Object object, run the code:
Run results: size: 3
This result is very simple, first determine hashCode r1 and r2 target object, since hashCode method object returns the conversion result of the object is local memory addresses, hashCode different instance of an object is not the same, the same as R3 and r1 hashCode also unequal, but == r1, r1, the final set only the collection r1, r2, r3 three objects, the size is 3

Let's contents equals method RectObject object of comments, direct return false, no comments hashCode method, run the code:
Run results: size: 3 This result is somewhat unexpected, we analyze:
First r1 and r2, hashCode object comparison, are not equal, so r2 into the set, and then look at r3, r1 and compare hashCode method r3 is equal, then compare the two of them equals method, because the equals method always returns false, so r1 and r3 is not equal, r2 and r3 Needless to say, they are hashCode two are not equal, so r3 into the set, the look r4, r1 and r4 found relatively equal hashCode, equals method in comparison, because equals return false, so r1 and r4 are not equal, the same r2 and r4 is also unequal, r3 and r4 is not equal, so r4 can be placed in the collection set, then the result should be the size: 4, why would it be 3 ?
This time we need to see HashSet source, here is the source code for the add method in HashSet:

/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这里我们可以看到其实HashSet是基于HashMap实现的,我们在点击HashMap的put方法,源码如下:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

ModCount ++;
the addEntry (the hash, Key, value, I);
return null;
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
30
31 is
our main look if the determination condition,
first determines whether hashCode equal, not equal, then skip, equal, then again compares the two objects are equal or two objects equals method, because of the operation or , so long as one can be set up, where we can explain that, in fact, the size of the collection is above 3, because the last one did not put in r1, that returns true r1 == r1, so do not go into the . So the size of the collection is 3, if we set the hashCode method always returns false, then this collection is a 4.

Finally, we look at the problem in perspective hashCode cause of memory leaks: look at the code:

package com.weijia.demo;
import java.util.HashSet;
public class Demo {
public static void main(String[] args){
HashSet<RectObject> set = new HashSet<RectObject>();
RectObject r1 = new RectObject(3,3);
RectObject r2 = new RectObject(5,5);
RectObject r3 = new RectObject(3,3);
set.add(r1);
set.add(r2);
set.add(r3);
r3.y = 7;
System.out.println("删除前的大小size:"+set.size(http://www.my516.com));
set.remove(r3);
System.out.println("删除后的大小size:"+set.size());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
: operating results
size size before deletion: 3
size size after deleting: 3
rub, found a problem, and it is a big problem Yeah, we call remove Remove r3 object that is deleted r3, but in fact not removed, this is called memory leaks, is not an object but he is still in memory. After so many times we operate, the memory burst. Remove look at the source code:
/ **
. * Removes specified at The Element from the this the SET IF IT IS Present
* More formally, Removes AN Element <tt> E </ tt> SUCH that
* <tt> (O == null E? null ==: o.equals (E)) </ TT>,
* IF SET the contains the this SUCH AN Element Returns <TT> to true </ TT> IF.
* The Element Contained the this SET (or equivalently, the this IF SET
* changed The Call A Result of AS). (This Will Not Contain The SET
* Once Element The Call Returns.)
*
* @param O removed from the this Object to BE SET, IF Present
* @return <tt>true</tt> if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后再看一下remove方法的源码:
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
在看一下removeEntryForKey方法源码:
/**
* Removes and returns the entry associated with the specified key
* in the HashMap. Returns null if the HashMap contains no mapping
* for this key.
*/
final Entry<K,V> removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;

while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}

E return;
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
30
31 is
we have seen, at the time of invoking the remove method, will first use the object the hashCode value to find the object, and then delete it, this problem is because we have modified the value of the y property r3 object, and because the object's hashCode method RectObject have involved in computing the value of y, so hashCode r3 object took place in change, so remove method does not find r3, so delete failed. That's r3 hashCode changed, but he did not update the stored location, still in its original position, so when we went to his new hashCode must be found.
---------------------

Guess you like

Origin www.cnblogs.com/ly570/p/11331593.html