HashSet、HashMap
来源:互联网 发布:js split 数组 length 编辑:程序博客网 时间:2024/06/07 01:05
HashSet添加元素方法的本质也是调用HashMap
HashMap实现原理:
移位、^运算=hash值
能否添加进HashMap集合当中呢?
3个依据:判断hash值、是否为同一对象、equals方法是否相等
e.hash == hash && ((k = e.key) == key || key.equals(k))
Entry<K,V> e = table[i]; e != null; e = e.next//取桶里的对象,如果桶里没有对象即立刻添加进来,如果有需要,可以进行桶的扩容
void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); } void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); size++; }
Entry<K,V> e = table[i]取桶里的对象,如果桶里没有对象即立刻添加进来,如果有对象则判断桶里的hash值是否等于要放进桶里的对象的hash值,如果相等,再判断是否为同一个对象。Entry<K,V> e = table[i]取桶里的对象,判断桶里的hash值和将要放进桶里的对象的hash值是否相等,如相等,再判断是否为同一个对象,根据(k = e.key) == key的key值来做判断,如果为同一个对象,说明桶里已经存在该key则为同一个对象, V oldValue = e.value即用药放进桶里的value值取代原来桶里的value值。Entry<K,V> e = table[i]即用来取桶里的元素,有可能存在,也有可能不存在,如果hash值一样即e.hash == hash为true,但是(k = e.key) == key 为false,说明不是同一个对象。再判断key.equals(k)即判断该对象的equals方法是否相等。如果相等, V oldValue = e.value即用药放进桶里的value值取代原来桶里的value值。
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key); //计算新hash 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++; addEntry(hash, key, value, i); return null; }
int hash(key)=原hash移位得到新hash并和原hash进行^异或运算
final int hash(Object k) { int h = 0; if (useAltHashing) { if (k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h = hashSeed; } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
e = e.next创建新节点
static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; int hash; /** * Creates new entry. */ Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; }
===================================
判断HashSet集合是否已经存在某个对象
代码:
package com.zbiti.java;import java.util.HashSet;import java.util.Set;import org.junit.Test;public class SetDemo { public static void main(String[] args) { } @Test public void test1(){ Set<Dog> dogs = new HashSet<Dog>(); dogs.add(new Dog("white")); dogs.add(new Dog("white")); System.out.println(dogs.contains(new Dog("white"))); //fasle }}class Dog{ private String name; public Dog(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
结果:输出false
原因:HashSet的contains方法的实现如下:
public boolean contains(Object o) { return map.containsKey(o); }
public boolean containsKey(Object key) { return getEntry(key) != null; }
final Entry<K,V> getEntry(Object key) { int hash = (key == null) ? 0 : hash(key); 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; }
解读:
int hash = (key == null) ? 0 : hash(key);先判断添加方法里是否有对象,如果有对象计算出新hash值, for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null;e = e.next) 先判断桶里是否有对象,如果有对象取出对象 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; return null; 判断hash值是否相等,即放进桶里对象和已经存在桶里对象的hash值是否相等。如不想等,返回null,说明桶里不存在该对象。 如相等,再判断对象是否为同一个对象。 如果是同一对象,返回该对象。 如果不是同一个对象,再判断对象的equals是否相等,即桶里的对象和将要放进桶里的对象的equals方法的比较。
代码:
package com.zbiti.java;import java.util.HashSet;import java.util.Set;import org.junit.Test;public class SetDemo { public static void main(String[] args) { } @Test public void test1(){ Set<Dog> dogs = new HashSet<Dog>(); dogs.add(new Dog("white")); dogs.add(new Dog("white")); System.out.println(dogs.contains(new Dog("white"))); //false }}class Dog{ private String name; public Dog(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { return 1; }}
结果:输出false
分析:Dog类的hashCode方法被我们重写了,根据上面的分析,桶里2只dog和contains里的dog的hash值是一样的都为1,。所以需要再判断是否 为同一个对象,明显通过new 产生了新的对象,所以并不是同一个对象。直接返回了null。
代码:
package com.zbiti.java;import java.util.HashSet;import java.util.Set;import org.junit.Test;public class SetDemo { public static void main(String[] args) { } @Test public void test1(){ Set<Dog> dogs = new HashSet<Dog>(); Dog d1 = new Dog("white"); Dog d2 = new Dog("white"); dogs.add(d1); dogs.add(d2); System.out.println(dogs.contains(new Dog("white"))); //true }}class Dog{ private String name; public Dog(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { return 1; } @Override public boolean equals(Object obj) { return true; }}
结果:输出true
分析:桶里含有2个Dog对象,HashSet调用contains方法传进了一个新的Dog对象,由于Dog类里的hashcode、equals方法都被我们重写了,所以不管创建多少个对象,它们调用hashcode、equals方法的返回值都是一样的。根据HashMap的实现原理判断的3个原则,hash值相等,尽管对象不一样,但是equals返回值相等即说明桶里存在该对象。
代码:
package com.zbiti.java;import java.util.HashSet;import java.util.Set;import org.junit.Test;public class SetDemo { public static void main(String[] args) { } @Test public void test1(){ Set<Dog> dogs = new HashSet<Dog>(); Dog d1 = new Dog("white"); Dog d2 = new Dog("white"); dogs.add(d1); dogs.add(d2); System.out.println(dogs.contains(new Dog("white"))); //false }}class Dog{ private String name; public Dog(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { return 1; } @Override public boolean equals(Object obj) { return false; }}
结果:输出false
分析:Dog类hashcode()、equals()被我们重写,调用hashcode返回的值是相等的,由于对象不是同一个对象并且调用equals方法返回false,所以输出的结果为false。
代码:
package com.zbiti.java;import java.util.HashSet;import java.util.Set;import org.junit.Test;public class SetDemo { public static void main(String[] args) { } @Test public void test1(){ Set<Dog> dogs = new HashSet<Dog>(); Dog d1 = new Dog("white"); Dog d2 = new Dog("white"); dogs.add(d1); dogs.add(d2); System.out.println(dogs.contains(d1)); } //true}class Dog{ private String name; public Dog(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { return 1; } @Override public boolean equals(Object obj) { return false; }}
结果:输出true
分析:Dog类hashcode()、equals()被我们重写,调用hashcode返回的值是相等的,由于桶里的对象存在和将要放进桶里的对象是同一个对象,尽管调用equals方法返回false,结果的输出依然为true。
- Hashmap hashset
- hashmap,hashset
- HashMap,HashSet
- HashSet、HashMap
- HashSet、HashMap
- HashMap&&HashSet
- HashSet HashMap
- hashmap,hashset
- hashSet,hashMap
- HashSet、HashMap
- HashMap, HashSet, HashMap Iterator
- HashMap 、 HashSet 、 HashTable
- HashMap 、 HashSet 、 HashTable
- HashMap, HashTable, HashSet区别
- hashset,hashmap的区别
- HashSet 、HashMap 和 HashTable
- 遍历hashMap、hashSet、Hashtable
- 遍历hashMap、hashSet、Hashtable
- Mysql对已有数据表进行分区
- 唯快不破:TCP/IP详解--举例明白发送/接收缓冲区、滑动窗口协议之间的关系
- 第十一周 项目4 — 利用遍历思想求解图问题(6)
- 通过HttpURLConnection连接服务器,发送报文,获取服务器报文返回
- Linux企业运维人员最常用150个命令汇总
- HashSet、HashMap
- CAMWorks.For.Solid.Edge.2017.SP2.Win64 1DVD
- python中的pickle模块
- 分享一些实用的工具类
- js生成随机不重复ID
- 将数据写到本地的某个文件夹下
- 第8章 无线AP的实现
- bzoj 3811: 玛里苟斯(期望+线性基)
- java中调用cmd命令