由浅入深解析HashMap---HashMap简单实现 增、删、查。

如果让我们自己来设计HashMap,应该怎么做呢?数组。用数组存储节点,每个节点有key和value信息。那首先我们得要有节点存储key,value。

节点设计

在这个Node类中,有三个属性,hash值、key、value值。

 1 class Node<K,V> {
 2         final int hash; //hash值
 3         final K key;//key
 4         V value;//value
 5 //构造函数
 6         Node(int hash, K key, V value, Node<K,V> next) {
 7             this.hash = hash;
 8             this.key = key;
 9             this.value = value;
10             this.next = next;
11         }
12
13         public final K getKey()        { return key; }
14         public final V getValue()      { return value; }
15         public final String toString() { return key + "=" + value; }
16
17         public final boolean equals(Object o) {
18            if (o == this)
19              return true;
20                if (Objects.equals(key, o.getKey()) &&
21                    Objects.equals(value, o.getValue()))
22                    return true;
23
24             return false;
25         }
26 }

注意:这里的构造函数中多了个next,大家忽略即可。奇怪,添加了这个代码块,怎么编辑的时候删除不了。哎。。。

初始化数组

定义一个容量为100的数组,用来存储node节点。 DEFAULT_INITIAL_CAPACITY ,它必须是必须是2的幂,在JDK提供的HashMap它的值为1 << 4,也就是16,这里直接填16不可以吗?为啥一定要这样写?

1  static final int DEFAULT_INITIAL_CAPACITY=100;
2  transient Node<K,V>[] table;
3     /**
4      * 构造函数
5      */
6     public SimpleHashMap()
7   {
8       table=(Node<K,V>[])new Node[DEFAULT_INITIAL_CAPACITY];
9   }

增加操作-put

对一个容量为100的数组中添加元素其实很简单,具体步骤如下:

1)对key值进行hash,获取hash值。

2)通过上面获取的hash值、key、value值,创建node节点。

3)通过hash值和数组长度获取对应的下标。

4)对获取的下标赋值。

注意:这里对key进行hash调用的hash函数,具体我也不明白为啥要这样设计?

1 static final int hash(Object key) {
2       int h;
3       return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
4   }

另外,根据hash值和容量(数组长度)获取对应的下标,具体我也不明白为啥要这样设计?

1 i = (n - 1) & hash

具体的put代码如下:

 1  public V put(K key, V value)
 2     {
 3         //创建新节点
 4         Node<K,V> p; int n, i;
 5         //获取长度
 6         n=table.length;
 7         //对key值进行hash
 8         int hash=hash(key);
 9         //目前没有考虑hash冲突
10         table[i = (n - 1) & hash]=newNode(hash,key,value);
11         //返回原来的值
12         return value;
13
14     }
15 //创建新节点
16  Node<K,V> newNode(int hash, K key, V value) {
17       return new Node<>(hash, key, value);
18   }

删除操作-remove

删除操作其实和添加差不多,首先要获取下标,然后再将下标的值赋值为null。

 1   public V remove(Object key) {
 2         Node<K,V> e;
 3         return (e = removeNode(hash(key), key)) == null ?
 4             null : e.value;
 5     }
 6     /**
 7      * 删除节点。
 8      * 目前不考虑冲突,当对应的下标有值且不为null时,返回该值,并将对应的值设置为Null
 9      * 这里考虑不太完善,因为hashmap是允许value为null的,这样并没有真正删除这个元素。
10      * @param hash
11      * @param key
12      * @return
13      */
14     final Node<K,V> removeNode(int hash, Object key) {
15         Node<K,V> p;int index;
16         p=table[index = (table.length - 1) & hash];
17         if(p!=null)
18         {
19             table[index]=null;
20         }
21         return p;
22     }

查询操作-get

和remove、put操作一样,也是需要根据key值获取下标,然后再返回对应的value值。

 1  /**
 2      * 根据key值,获取value值
 3      * @param key
 4      * @return
 5      */
 6     public V get(Object key) {
 7         Node<K,V> e;
 8         return (e = getNode(hash(key), key)) == null ? null : e.value;
 9
10     }
11     /**
12      * 获取对应的值
13      * @param hash
14      * @param key
15      * @return
16      */
17     final Node<K,V> getNode(int hash, Object key) {
18        return  table[(table.length - 1) & hash];
19     }

是否存在该元素--containskey

根据key值判断是否存在该元素,其实和get操作一样,只是这里返回的是布尔值。

1  /**
2      * 是否存在对于的key值
3      * @param key
4      * @return
5      */
6     public boolean containsKey(Object key) {
7         return getNode(hash(key), key) != null;
8
9     }

哇!是不是很简单呢?这里有两个疑问,就是不知道那个下标的获取和hash值得获取为啥要那样设计?是因为这样是最优的吗?下标的获取这种方法,发生冲突的几率就少很多吗?在整个系列中,我并没有讨论HashMap继承AbstractMap,实现Map接口。

时间: 2024-10-13 12:05:53

由浅入深解析HashMap---HashMap简单实现 增、删、查。的相关文章

MyBatis学习--简单的增删改查

jdbc程序 在学习MyBatis的时候先简单了解下JDBC编程的方式,我们以一个简单的查询为例,使用JDBC编程,如下: 1 Public static void main(String[] args) { 2 Connection connection = null; 3 PreparedStatement preparedStatement = null; 4 ResultSet resultSet = null; 5 6 try { 7 //加载数据库驱动 8 Class.forName

MyBatis3.2.2+SpringMVC3.0 简单实现(增删改查,Web版实现)

MyBatis3.2.2+SpringMVC3.0 简单实现(增删改查,Web版实现) 首先,需要知道Eclipse如何创建Dynamic Web Project for Maven,我们首先需要知道如何用Eclipse创建动态部署的Maven Web-app 项目.参考以下链接的博客:http://blog.csdn.net/smilevt/article/details/8215558. 构建完之后:实现具体的增删改查,不去部署Web war的时候我们用Junit单元测试CRUD功能.代码如

用CI框架向数据库中实现简单的增删改查

以下代码基于CodeIgniter_2.1.3版 用PHP向数据库中实现简单的增删改查(纯代码)请戳 http://www.cnblogs.com/corvoh/p/4641476.html CodeIgniter_2.1.3与PHP5.6的兼容问题请戳 http://www.cnblogs.com/corvoh/p/4649357.html 增: //insert//语法:$bool=$this->db->insert('表名',关联数组); $data=array( 'username'=

使用JDBC分别利用Statement和PreparedStatement来对MySQL数据库进行简单的增删改查以及SQL注入的原理

一.MySQL数据库的下载及安装 https://www.mysql.com/ 点击DOWNLOADS,拉到页面底部,找到MySQL Community(GPL)Downloads,点击 选择下图中的MySQL Community Server 选择想要的版本进行下载 之后的步骤,因为本人已经安装过MySQL数据库,而卸载重装会比较麻烦,卸载不干净会导致新的装不上,所以可以参考下面的博客,因为官网的改动,前面的部分已经与该博客不符,按照本人在上面的介绍寻找即可 https://blog.csdn

Mybatis使用之简单的增删改查

Mybatis使用之简单的增删改查 一:简介 主要记录最简单的数据的增删改查.下一章会有各个操作详细一点的配置说明.以Author表为例(见上一博客).Author表没有关联任何其他表.也没有特殊字段. 二:映射规则 2.1.映射文件中的sql方法与对应的XxxMapper接口中的方法映射规则: a)映射文件的namespace的值是XxxMapper接口的全限定名.即包名+接口名称 b)映射文件中表示增删改查的标签(select.insert.delete.update)的id的值是接口中方法

EF5(6) 简单三层 增删改查

1:项目结构 2:每层添加对其他层的引用,这里我们把除了Web层之外的所有的层生成的文件都放到解决方案下的Library文件夹下,然后每个项目分别来引用里面的dll项目文件. 我们在Model项目上,右键属性->生成-> 在下面的输出里面,选择上一级的 Library文件夹 2.2 我们调整项目的生成顺序 ,在解决方案或者是任意项目上右键,选择 生成依赖项,调整各个项目的依赖,这样的目的就是调整项目的生成顺序. 注意,这里你选择依赖项,并没有给项目与项目之间增加了dll的引用,只是单纯的修改了

通过JDBC进行简单的增删改查

通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操作 (1)定义记录的类(可选) (2)连接的获取 (3)insert (4)update (5)select (6)delete 四.测试 五.代码分析 六.思考问题 前言:什么是JDBC 维基百科的简介: Java 数据库连接,(Java Database Connectivity,简称JDBC)

用PHP向数据库中实现简单的增删改查(纯代码,待完善)

<?php $con = mysql_connect("localhost:3306","root",""); if (!$con) { die('Could not connect: ' . mysql_error()); } mysql_select_db("test", $con); $result = mysql_query("SELECT * FROM user"); echo "

entity framework—简单的增删改查

应用程序对数据库执行CRUD时,通过entity framework方式,实际上是对DbContext的操作,DbContext是EF的入口,DbContext拿到对应的消息(CRUD)后,通过ORM中的Mapping来将对象O映射成数据库中的关系R. 下面就简单的实现一下利用entity framework实现简单的增删改查.首先要说明的是我已经建立了在解决方案中映射了数据库中表"Customer".所有的操作都是针对这张表. 1.增加 Customer customer = new

通过JDBC进行简单的增删改查(以MySQL为例) 目录

通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操作 (1)定义记录的类(可选) (2)连接的获取 (3)insert (4)update (5)select (6)delete 四.测试 五.代码分析 六.思考问题 前言:什么是JDBC 维基百科的简介: Java 数据库连接,(Java Database Connectivity,简称JDBC)