赞
踩
Java中HashMap集合在JDK1.8版本时基于 数组+链表+红黑树实现的,查询效率为O(1)
使用内部类Entry来描述键值对对象
目录
创建了StudentEntity类并重写了toString方法,创建demo进行测试:
答案:可以
- public class demo {
- public static void main(String[] args) {
- HashMap<StudentEntity, String> hashMap = new HashMap<>();
- StudentEntity s1 = new StudentEntity("Mercedes", "22");
- StudentEntity s2 = new StudentEntity("Mercedes", "22");
- hashMap.put(s1,"OK");
- hashMap.put(s2,"OK");
- for (Map.Entry<StudentEntity,String> studentEntityStringEntry:
- hashMap.entrySet()) {
- System.out.println("key:"+studentEntityStringEntry.getKey().toString()+
- " value:"+studentEntityStringEntry.getValue());
- }
- }
- }
程序运行结果:
答案:无序,其底层采用散列机制存放数据
测试时我发现一个问题,当HashMap的key值被设置为Integer类型时,HashMap的存储就时有序的。
- public class demo {
- public static void main(String[] args) {
- HashMap<String, String> hashMap = new HashMap<>();
- for (int i = 0; i < 100; i++) {
- hashMap.put("k"+i,"v"+i);
- }
-
- hashMap.forEach((k,v)->{
- System.out.println(k+","+v);
- });
- }
- }
以上代码采用了一种比较新颖的Java集合基于范围的for循环遍历:
- hashMap.forEach((k,v)->{
- System.out.println(k+","+v);
- });
可替换为lambda表达式的方式:
hashMap.forEach((k,v)-> System.out.println(k+","+v));
程序运行结果:
答案:可以 null键值存放在HashMap底层数组的index为0的位置(HashTable的key不允许存放null值)
- hashMap.put(null,"Mercedes");
- hashMap.forEach((k,v)-> System.out.println(k+","+v));
可以为null值。
答:hash冲突问题是指:当要通过调用put方法存入两个对象时,这两个Entry对象的键的hashCode值相同,通过hashCode计算出的index值相同,所以会产生存入覆盖问题
- public class demo {
- public static void main(String[] args) {
- HashMap<Object, Object> hashMap = new HashMap<>();
- hashMap.put("a","a");
- hashMap.put(97,"97");
- System.out.println(hashMap.get("a"));
- }
- }
程序运行结果:
可以看到Java提供的集合已经解决了hash冲突问题(本人想到一种解决冲突办法:将HashMap泛化出来再使用)
JDK1.7是这样解决的:
将hashCode值相同的key存放在同一张链表中
以下是自定义的HashMap
- package lzx4;
-
- public class MyHashMap<K,V> {
- private Entry<K,V>[] entries = new Entry[10000]; //存放键值对的数组
- class Entry<K, V> {
- K k;
- V v;
- int hash; //当前对象的hashCode
- Entry<K,V> next; //当前对象的next指针
- public Entry(K k, V v,int hash) {
- this.k = k;
- this.v = v;
- this.hash = hash;
- }
-
- }
- public void put(K k,V v){
- int hash = k.hashCode();
- int index = hash%entries.length;
- Entry oldEntry = entries[index]; //拿到该对象后判断是否为空,为空则证明该位置是第一次存对象
- if(oldEntry == null){ //否则就将上一次存放的对象的next指针指向当前对象
- entries[index] = new Entry<>(k,v,hash);
- }else{
- oldEntry.next = new Entry<>(k,v,hash);
- }
- }
-
- public V get(K k){
- int hash = k.hashCode();
- int index = hash%entries.length;
- for(Entry<K,V> entry = entries[index];entry!=null;entry = entry.next){
- if(entry.hash == hash && (entry.k == k || entry.k.equals(k))){
- return entry.v;
- }
- }
- return null;
- }
-
- public static void main(String[] args) {
- MyHashMap<Object, Object> myHashMap = new MyHashMap<>();
- myHashMap.put("a","a");
- myHashMap.put(97,"97");
- System.out.println(myHashMap.get("a"));
- }
- }
get()方法思路:先得到传入的key的hashCode,得到index后找到该条链表所在的位置,然后通过next指针向后循环,先比较当前对象的k的hashCode和传入的key的hashCode是否相等,if中这个语句
entry.k == k || entry.k.equals(k))
前面entry.k == k方便自定义类型比较,后面的equals方法在本案例中配合hash值来比较判断该对象位于链表中的哪个位置,在这里,equals方法单纯就是比较值一不一样。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。