集合的概念:集合类存放的都是对象的引用,不是对象本身,我们称集合中的对象就是指集合中对象的引用(reference),存放在Java.util包中。
集合类型主要有3种:set(集)、list(列表)和map(映射)。
集合的特点是:可以改变长度,但不保证迭代顺序和不存放重复的数据
在集合中如何判断两个数据相等?
在集合中判断一个数据是否相等要根据它的HashCode方法和equlas方法来判断内容是否相等,我们在判断一个数据是否相等的时候,首先它会调用自己的HashSet方法计算出一个Code值,然后通过这个code值来找到数据在集合中的位置,如果code值的位置上没有数据就将这个数据存放在集合中,如果有,就调用equals方法比较两个数据的大小,如果相等就返回true,否则返回false,如果返回的是true就说明集合中已经有一个数据和你要存放的数据相等了,那就不要再将这个数据存放进去,HashSet不能存放两个相同的数据,如果你一定要将这个数据存入集合就要重写HashCode方法equals方法,因为怕和集合中的数据产生重复,如果重复了你不重写这两个 方法是不能放进去的(ps:一定要HashCode方法和equals方法都相等才能说数据相等,二者缺一不可)
下面是一些代码的实现:
向集合中存储数据
/** * 增加数据的方法 * * @param e */ public void add(E e) { Node<E> node = new Node<E>(e);// 创建一个新结点并指定数据 // 如果head指向的数据为空说明是一个空链表 if (head == null) { head = node;// 那么将head指向node last = node;// last也指向node,这时node即是头结点 也是尾结点 num++;// 结点数增加 } else { // 如果head不为空说明链表中有数据,调用isDuplicate方法,看要添加的数据和链表中的数据是否重复 boolean bool = isDuplicate(node); if (!bool) { // 根据node的hashcode值找到下标 int index = getIndex(node.code); // 调用insert方法,将数据插入在index位置 insert(index, e); num++;// 结点数增加 } } }
向集合中添加数据的时候调用插入方法在这里面对数据进行比较
/** * 定义一个私有的插入方法 * * @param index插入结点的下标 * @param e插入的内容 */ private void insert(int index, E e) { Node<E> node = new Node<E>(e);// 创建新结点并指定数据 // 插入的结点位置是头结点的位置 if (index == 0) { node.next = head;// 将node的下一个结点指向head head.front = node;// head的上一个结点指向node head = node;// 将head指向 node,这时node中的数据处于第一个head的位置 } // 其他位置 else { // 创建一个新结点,调用getNode(index)方法找到我们要插入数据的结点的位置 Node<E> n1 = getNode(index); Node<E> n2 = n1.front;// 再创建一个结点,将我们找到n1位置的上一个结点指向n2 // 将node插在n2和n1的中间,n2->node->n1,所以 n2.next = node;// n2的下一个结点指向node node.front = n2;// node的上一个结点 指向n2 node.next = n1;// node的下一个结点指向n1 n1.front = node;// n1的上一个结点指向node // 上面这一操作主要是在n2和n1的中间插入node结点,必须得改变他们的指向关系 } }
获取数据的方法
/** * 取出并移除一个数据 * * @return返回取出数据的内容 */ public E get() { // 看头结点是否为空,不为空才继续下面的操作否则返回null if (head != null) { Node<E> n = head;// 定义一个新结点指向head head = head.next;// 将head指向它的下一个结点 n.next = null;// 将新结点n的下一个结点指向null num--; return n.data;// 返回原来head的值 } return null; }
删除数据提供了两种不同的方法
①根据下标删除数据
/** * 根据下标删除数据 * * @param index要删除数据的下标 */ public void delete(int index) { Node<E> n = getNode(index);//创建一个新结点并根据下标获取需要删除的数据的位置 //三者的位置n1->n->n2 Node<E> n1 = n.front;//n1指向n的前一个结点 Node<E> n2 = n.next;//n2指向n的下一个结点 //下面将实现删除n结点 n2.front = n1; n1.next = n2; n.front = null; n.next = null; num--; }
②根据内容删除数据
/** * 根据内容删除数据的方法 * * @param e */ public void delete(E e) { Node<E> node = head;//创建新结点指向head int code = e.hashCode();//获得结点e的hashCode值 while (node != null) {//node结点指向的数据不为null,进入循环 //判断node的hashCode和内容是否等于e的hashCode和内容,相等就获取node的下标调用根据下标删除内容的方法 if (node.data.equals(e) && node.code == code) { int m = getIndex(node.code); delete(m); } node = node.next; } }
判断集合中是否有结点数据与要添加的数据相同的数据
/** * 判断集合中是否有结点数据与要添加的数据相同的数据 * * @param node要添加的数据 * @return如果相同返回ture,没有相同的就返回false */ private boolean isDuplicate(Node<E> node) { Node<E> n = head;// 定义一个新结点指向head // 如果n指向的结点数据不为空就赶进入循环 while (n != null) { // 判断n所指向 的数据和传入的数据的内容和code值 是否相等,相等返回true,否则n指向下一个结点 if (n.data.equals(node.data) && n.code == node.code) { return true; } n = n.next; } return false; }
根据结点的hashcode值计算出结点的位置
/** * 根据结点的hashcode值计算出结点的位置 * * @param code * 结点的hashcode值 * @return返回结点的位置 */ private int getIndex(int code) { int t = -1;// 定义一个变量t给它赋值为一个不存在的值 Node<E> node = head;// 定义一个新的结点指向head // 如果Node所指向结点的数据不为null,就进入循环 while (node != null) { t++;// 这时变量t增加 // 如果node的hashcode值大于等于我们要查找的数据的hashcode就退出循环,否则指向下一个结点 if (node.code >= code) { break; } node = node.next; } return t; }
根据下标确定结点
/** * 根据下标确定结点 * * @param index查找结点的下标 * @return返回的结点的内容 */ private Node<E> getNode(int index) { int t = -1;// 定义一个变量赋值为一个不存在的值 // 判断我们在查找的下标是否在结点数范围内 if (index >= 0 && index < num) { Node<E> node = head;// 创建新结点指向head // 如果node结点所指向的数据不为空就进入循环 while (node != null) { // 这时t增加到0,从下标的最小值,如果前面定义的时候从0开始,这时再增加t就已经不再是下标的最小值,就和我们需要的结点对不上 t++; // 如果t和Index相等就说明找到就退出程序,否则指向下一个结点继续循环 if (t == index) { break; } node = node.next; } return node; } else { // 抛出异常 throw new IndexOutOfBoundsException("下标超出边界!index:" + index + ",size:" + num); } } }
相关推荐
HashSet的实现原理 ,HashSet与HashMap的区别 以及 HashSet的底层实现方式
hashSet底层去重原理
利用hashset产生不重复随机数的函数,附含测试数据; 调用方法 int[] arr=noDup(max,num),max为最大的数,num为要产生的随机数个数
源码解析jdk7.0集合:HashSet的底层实现原理.pdf
java HashSet 集合排序,需要通过利用TreeSet集合排序。2013-10-30。
HashSet 是 Java 中的一个集合类,它实现了 Set 接口并提供了基于哈希表的无序、不重复元素的集合。具体来说,它是通过哈希表(实际上是一个 HashMap 实例)来存储元素的。 以下是 HashSet 的一些主要特点: 无序...
向 HashSet 中 add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合 equles 方法比较。
对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码:
HashSet集合保证元素一致性
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
主要介绍了hashset去除重复值原理实例解析,具有一定借鉴价值,需要的朋友可以参考下。
简述了HashSet去重原理
图文并茂,能让大家很好的理解java中这个重要的知识点。 此文档需要wps或者office软件来查看,如果你没有此软件,到http://www.wps.com.cn 下载wps即可查看此文档。 注:本人所有资源都是共享的,的资源分都是0!
HashTable不支持空键值对! 而HashMap支持空键值对!
线程安全和线程不安全的分别有哪些? Map接口有哪些实现类? 描述一下Map put的过程 如何得到一个线程安全的Map? HashMap有什么特点? ConcurrentHashMap是怎么分段分组的? ConcurrentHashMap是怎么分段分组的? ...
HashSet 是一个没有重复元素的集合。 它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素。 HashSet是非同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它...
Set是java中一个不包含重复元素的collection。更正式地说,set 不包含满足e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。 HashSet与TreeSet...
hashMap可以通过一个键值与一个对象一一对应的关系找到我们要找的对象,再调用对象里面的方法