手动实现一个HashMap集合

说起HashMap的强大之处,就是其内部使用了哈希算法和链表算法,充分利用好加载因子的强大推动,使得在时间和空间上的成本寻求一种折中,其内部元素在存储和提取不仅可以充分利用好HashMap初始化的空间,而且查询效率及其的高!

在面试中,面试官会常问HashMap的底层源码的实现,接下来我简单的手动实现一个HashMap集合:

(一)HashMap中存储的元素类型即为键值对存在,定义一个能包含键值对的内部类:


  
  
  1. class MapEntry {
  2. Object key;
  3. Object value;
  4. public MapEntry(Object key, Object value) {
  5. super();
  6. this.key = key;
  7. this.value = value;
  8. }
  9. }

(二)我们使用java.util.LinkedList双向链表来模拟HashMap中底层实现的数组(即链表数组)


  
  
  1. /**
  2. * 1.提高查询的效率 2.默认加载因子 (0.75) 即在时间和空间成本上寻求一种折衷。加载因子过大存储空间能得到充分利用,但查询效率会低一点;
  3. * 加载因子过小,存储空间利用率降低,但是查询速度会高一点!(加载因子的设计大小要保证存储空间充分利用,且查询效率高)
  4. */
  5. public class ManualHashMap {
  6. LinkedList[] arr = new LinkedList[ 999]; // 键值对集合! Map底层结构是:数组 + 链表
  7. int size = 0; // HashMap的容量
  8. // 构造方法
  9. public ManualHashMap() {
  10. }
  11. /*
  12. * 向HashMap中存入键值对
  13. */
  14. public void put(Object key, Object value) {
  15. MapEntry node = new MapEntry(key, value);
  16. /*
  17. * 获取该键值对在数组中的索引位置(0~998);
  18. * 重写HashCode()方法就是为了让具有相同属性对象具有相同的HashCode值(地址码);
  19. * 由于重写HashCode()方法在任何种程度上,都会出现一定的Bug,使得具有不同属性值都会有相同的HashCode码值;
  20. * 此时就需要重写equals()方法,进行二次比较key值是否相同,就可做到万无一失了!
  21. */
  22. int hash = node.key.hashCode() % arr.length;
  23. hash = hash < 0 ? -hash : hash;
  24. if (arr[hash] == null) { // 此索引位置为空
  25. LinkedList<MapEntry> list = new LinkedList<>(); //创建一个双向链表
  26. arr[hash] = list;
  27. list.add(node);
  28. size++;
  29. } else { // 该位置有元素
  30. LinkedList<MapEntry> list = arr[hash]; // 取出该索引处的链表
  31. // 判断有没有键值重复
  32. boolean flag = false; //判断此链表中,是否存在重复的键值
  33. for ( int i = 0; i < list.size(); i++) {
  34. MapEntry temp = (MapEntry) list.get(i);
  35. if (temp.key.equals(key)) { // 键值有重复
  36. temp.value = value; // value值覆盖
  37. flag = true;
  38. }
  39. }
  40. if(!flag){ //不存在重复的key,需添加此元素
  41. list.add(node);
  42. size++;
  43. }
  44. }
  45. }
  46. /*
  47. * 获取键值对中某个键值对对象
  48. */
  49. public Object get(Object key) {
  50. int hash = key.hashCode() % arr.length;
  51. hash = hash < 0 ? -hash : hash;
  52. if (arr[hash] != null) {
  53. LinkedList<MapEntry> list = arr[hash];
  54. for ( int i = 0; i < list.size(); i++) {
  55. MapEntry temp = (MapEntry) list.get(i);
  56. if(temp.key.equals(key)){
  57. return temp.value;
  58. }
  59. }
  60. }
  61. return null;
  62. }
  63. public static void main(String[] args) {
  64. ManualHashMap map = new ManualHashMap();
  65. map.put( "6", "b");
  66. map.put( "6", "a");
  67. map.put( "5", "c");
  68. map.put( "4", "d");
  69. System.out.println(map.size); //3
  70. System.out.println(map.get( "6")); //a
  71. }
  72. }
本人只是简单的实现了HashMap存取数据的详细过程,加载因子以及数组的扩容再次赋值,过于繁琐,若需理解深透,请自行查阅HashMap底层的源代码!

猜你喜欢

转载自blog.csdn.net/lilinsqq/article/details/82494590
今日推荐