Java语言中HashMap集合面试常问问题

Java中HashMap集合在JDK1.8版本时基于 数组+链表+红黑树实现的,查询效率为O(1)

使用内部类Entry来描述键值对对象

目录

1.HashMap的key是否可以为自定义对象?

2.HashMap集合存储数据时是有序还是无序?

 3.HashMap key是否可以为null值?

4.什么是hash冲突问题?如何解决hash冲突问题?


创建了StudentEntity类并重写了toString方法,创建demo进行测试:

1.HashMap的key是否可以为自定义对象?

答案:可以

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());
        }
    }
}

程序运行结果:

2.HashMap集合存储数据时是有序还是无序?

答案:无序,其底层采用散列机制存放数据

测试时我发现一个问题,当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));

程序运行结果:

 3.HashMap key是否可以为null值?

答案:可以  null键值存放在HashMap底层数组的index为0的位置(HashTable的key不允许存放null值)

hashMap.put(null,"Mercedes");
hashMap.forEach((k,v)-> System.out.println(k+","+v));

 可以为null值。

4.什么是hash冲突问题?如何解决hash冲突问题?

答: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方法单纯就是比较值一不一样。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay/.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值