JAVA-集合

前言

文章内容摘抄自尚硅谷,纯属个人记录,如有侵权,随时删除

内存层面需要针对于多个数据进行存储。此时,可以考虑的容器有:数组、集合类

数组存储多个数据方面的特点:

  • 数组一旦初始化,其长度就是确定的
  • 数组中的多个元素是依次紧密排列的,有序的,可重复的
  • (优点)数组一旦初始化完成,其元素的类型就是确定的。不是此类型的元素,就不能添加到此数组中
  • (优点)元素的类型既可以是基本数据类型,也可以是引用数据类型。
int[] arr =new int[10];
arr[0]= 1;
arr[1]="AA";//编译报错

0bject[] arr1 =new 0bject[10];
arr1[0]= new string();
arr1[1]=new Date();

数组存储多个数据方面的弊端:

  • 数组一旦初始化,其长度就不可变了
  • 数组中存储数据特点的单一性
  • 对于无序的、不可重复的场景的多个数据就无能为力
  • 数组中可用的方法、属性都极少
  • 具体的需求,都需要自己来组织相关的代码逻辑
  • 针对于数组中元素的删除、插入操作,性能较差。

Java集合框架体系(java.util包下)

java的集合分为两大类:java.util.Collection、java.util.Map

Collection:存储一个一个的数据

  • 子接口:List:存储有序的、可重复的数据----"动态"数组 :ArrayList、LinkedList、Vecter
  • 子接口:Set:存储无序的、不可重复的数据:HashSet、LinkedHashSet、TreeSet(这三种Set的底层实现,分别对应了map的三种类型)

Map:存储一对一对的数据:

  • HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
    在这里插入图片描述

List

ArrayList

  • List的主要实现类
  • 线程不安全的、效率高
  • 底层使用0bject[ ]
  • 数组存储在添加数据、查找数据时,效率较高
  • 在插入、删除数据时,效率较低
// jdk8之后的版本中
// 如下代码的执行:底层会初始化数组,即:Object[]elementData= new Object[]{};
ArrayList<String>list =new ArrayList<>();
//首次添加元素时,会初始化数组,即:elementData= new 0bject[10];elementData[0]="AA'
list.add("AA");
// 当要添加第11个元素的时候,底层的elementData数组已满,则需要扩容。
// 默认扩容为原来长度的1.5倍。并将原有数组中的元素复制到新的数组中。

LinkedList

  • 底层使用双向链表的方式进行存储
  • 线程不安全
  • 在对集合中的数据进行频繁的删除、插入操作时,建议使用此类
  • 在插入、删除数据时,效率较高
  • 在添加数据、查找数据时,效率较低

Vector

  • List的古老实现类
  • 线程安全的、效率低
  • 底层使用0bject[]数组存储

总结
1、Vector基本不使用了。
2、ArrayList底层使用数组结构,查找和添加(尾部添加)操作效率高,时间复杂度为0(1),删除和插入操作效率低,时间复杂度为0(n)
3、LinkedList底层使用双向链表结构,删除和插入操作效率高,时间复杂度为0(1),查找和添加(尾部添加)操作效率高,时间复杂度为0(n)(有可能添加操作是0(1)
4、在选择了ArrayList的前提下,new ArrayList():底层创建长度为10的数组。还可以指定初始化长度new ArrayList(int capacity):底层创建指定capacity长度的数组。


Map

HashMap

  • 主要实现类
  • 线程不安全的,效率高
  • 可以添加null的key和valve值
  • 底层使用数组+单向链表+红黑树结构存储

HashMap中元素的特点

HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key就构成一个Set集合。
HashMap中的所有的value彼此之间是可重复的、无序的。所有的valve就构成一个Collection集合。
HashMap中的-个key-value,就构成了-个entry。
HashMap中的所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合。

添加/修改的过程(JDK1.7):

  1. 将(key1,valve1)添加到当前的map中
  2. 首先,需要调用key1所在类的hashCode()方法,计算key1对应的哈希值1,此哈希值1经过某种算法(hash())之后,得到哈希值2。
  3. 哈希值2再经过某种算法(indexFor())之后,就确定了(key1,valu1)在数组table中的索引位置i
  4. 如果此索引位置i的数组上没有元素,则(key1,value1)添加成功
  5. 如果此索引位置i的数组上有元素(key2,value2),则需要继卖比较key1和key2的哈希值2(此时称之为哈希冲突)
  6. 如果key1的哈希值2与key2的哈希值2不相同,则(Hey1,value1)添加成功。(一般使用链表,即索引同一位置上,有多个entry。链表过长会影响map得性能,因此底层还会有偏移值,尽量避免哈希冲突)
  7. 如果key1的哈希值2与key2的哈希值2相同,则需要继续比较key1和key2的equals()。要调用key1所在类的equals(),将key2作为参数传递进去
  8. 调用equals(),返回false:则认为(key1,valve1)添加成功。
  9. 调用equals(),返回true:则 key2是相同的。默认情况下,valve1会覆盖替换原有的value2。

在jdk8中,如果当前的(key,valve)经过一系列判断之后,可以添加到当前的数组角标i中。如果此时角标i位置上有元素。在jdk7中是将新的(key,value)指向已有的旧的元素(头插法),而在jdk8中是旧的元素指向新的(key,valve)元素(尾插法)。“七上八下”。
idk7:数组+单向链表4
jk8:数组+单向链表 +红黑树

什么时候会使用红黑树?
如果数组索1位置上的元素的个数达到8,并且数组的长度达到64时,我们就将此索引1位置上的多个元素改为使用红黑树的结构进行存储。

什么时候会使用红黑树变为单向链表?
当使用红黑树的索引1位置上的元素的个数低于6的时候,就会将红黑树结构退化为单向链表。

LinkedHashMap

  • 是HashMap的子类
  • 在HashMap使用的数据结构的基础上,增加了一对双向链表
  • 用于记录添加的元素的先后顺序,进而我们在遍历元素时,就可以按照添加的顺序显示
  • 开发中,对于频繁的遍历操作,建议使用此类。

TreeMap

  • 底层使用红黑树存储
  • 可以按照添加的key-value中的key元素的指定的属性的大小顺序进行遍历。
  • 需要考虑使用①自然排序 ②定制排序。

Hashtable

  • 古老实现类
  • 线程安全的,效率低
  • 可以添加null的Key或value值
  • 底层使用数组+单向链表结构存储

Properties:

  • 其key和valve都是String类型。常用来处理属性文件。

Set

存储无序的、不可重复的数据

HashSet

主要实现类;底层使用的是HashMap,即使用数组+单向链表+红黑树结构进行存储。(jdk8中是HashSet的子类;在现有的数组+单向链表+红黑树结构的基础上,又添加了一组双向链表

LinkedHashSet

用于记录添加元素的先后顺序。即:我们可以按照添加元素的顺序实现遍历。便于频繁的查询操作。

Treeset

底层使用红黑树存储。可以按照添加的元素的指定的属性的大小顺序进行遍历。

无序性

这里是根据添加的元素的哈希值,计算的其在数组中的存储位置。此位置不是依次排列的,表现为无序性。

不可重复性

添加到Set中的元素是不能相同的。
比较的标准,需要判断hashcode()得到的哈希值以及equals()得到的boolean型的结果。
哈希值相同且equals()返回true,则认为元素是相同的。

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值