Java学习记录-集合


总体概括

Collection

Iterator说明

迭代器,是一种设计模式,专门为容器遍历而设计,每次调用iterator()都会得到一个全新的迭代器对象,游标在第一个元素之前。

  1. next()将指针下移,将此处元素返回;
  2. hasNext()判断下一位是否有元素;
  3. remove()将元素删除,若未调用next()方法则不能remove,或者在上一次remove后不能再次remove(一个next()不能remove两次)

List

元素有序,可重复;以下三者都实现了List接口,存储特点相同:

ArrayList

List接口的主要实现类,线程不安全,效率高;底层使用Object[](elementData)存储,只是对数组封装;
源码分析:

  • jdk7:
    ArrayList list = new ArrayList();
    底层初始化了一个容量为10的Object[] elementData;
    add(123);elementData[0]=new Integer(123);若此时容量不够,则扩容,默认为原来容量的1.5倍,同时将旧数组copy到新数组中。
    建议开发中默认初始化容量,防止扩容次数过多
  • jdk8:
    ArrayList list = new ArrayList();
    底层初始化了Object[] elementData = {}
    第一次调用时才初始化一个长度为10的数组,再添加数据;
    总结:7中类似于单例模式的饿汉式,8类似于懒汉式

LinkedList

底层使用双向链表存储,对于频繁插入、删除操作,此类型效率高;
源码分析:
LinkedList list = new LinkedList();内部声明了Node类型的first和last属性,默认值为null

//Node节点
private static class Node<E>{
	E item;
	Node<E> next;
	Node<E> prev;
	Node(Node<E>,prev,E element,Node<E next){
		this.prev=prev;
		this.item=item;
		this.next=next;
	} 
}	

Vector

List接口的古老实现类,线程安全,公共方法都用了synchronized关键字
源码分析:
构造器初始化了一个容量为10的数组,默认扩容为原来的2倍

Set

存储无序的、不可重复的。

  1. 无序性:不等于随机性。存储的数据在底层数组中并非按照数组的索引顺序添加,而是根据数据的哈希值判断;
  2. 不可重复性:保证添加的元素按照equals判断时不能返回true;即相同的元素不能填加进来。
  3. 注意:
  • Set接口中没有额外的方法,都是Collection中声明的方法;
  • 向Set中添加的数据,其所在类一定要重写hashCode和equals方法;
  • 重写的两个方法尽可能保持一致性:相等的对象必须要相等的散列码。
  1. 添加元素的过程(HashSet):
  • 向HashSet中添加元素a,首先调用a所在类的hashCode方法,计算a的哈希值,此哈希值接着通过某种算法计算出在底层HashSet数组中的存放位置(索引位置),判断此位置上是否有元素:
  • 如果此位置上没有其他元素,则a添加成功。—情况1
  • 如果此位置上有其他元素b(或者以链表形式存在的多个元素),则比较a和b的哈希值:
    如果哈希值不相同,则a添加成功。—情况2
    如果哈希值相同,进而需要调用元素a所在类的equals方法:
    equals返回true,a添加失败;
    equals返回false,a添加成功;—情况3
    对于2,3添加成功时:元素a与其他元素在指定索引位置上以链表形式存储;
    7:头插法,8尾插法;

HashSet

作为Set接口的主要实现类,线程不安全的,可以存储null值,底层是数组加链表形式;

LinkedHashSet

作为HashSet的子类,遍历内部数据时,可以按照添加的顺序遍历;
再添加数据时,每个数据还维护了两个引用,记录此数据前一个和后一个数据;
对于频繁的遍历操作时,效率高于HashSet。

TreeSet

  1. 可以按照添加对象的指定属性,进行排序。
  2. 向TreeSet集合中添加的数据,必须是相同类的对象;
  3. 两种方法排序:
  • 自然排序(实现comparable接口):比较两个对象是否相同的标准为:compareTo返回0,不再是equals()
  • 定制排序:比较两个对象是否相同的标准为:Compartor接口的compare()实现方法返回0,不再是equals。

Map

双列数据,存储key-value对的数据。

HashMap

  1. 是Map的主要实现类;线程不安全的,效率高;可以存储key、value为null的数据。
  2. 底层结构:数组+链表(jdk7),数组+链表+红黑树(jdk8)
  3. Map的结构理解:
  • Map中的key:无序的,不可重复的,使用Set存储所有的key;key所在的类要重写equals和hashCode方法(HashMap为例);
  • Map中的value:无序的,可重复的,使用Collection存放(单列数据);value所在的类要重写equals方法;
  • 一个键值对:kay-value构成了一个Entry对象;
  • Map中的entry,无序的,不可重复的,使用Set存放所有的entry。
  1. HashMap的底层实现原理:
    JDK7
  • HashMap map = new HashMap();
    实例化以后,底层创建了长度为16的一维数组Entry[] table;
  • …可能执行过多次put操作…
  • map.put(key1,value1);
    首先调用key1所在类的hashCode方法(再加上hash()里面的运算)计算哈希值,此哈希值接着通过某种算法计算出在底层Entry数组中的存放位置(索引位置):
    如果 此位置上的数据为空,则entry添加成功。—情况1
    如果 此位置上的数据不为空(意味着此位置上存在一个或多个(链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
    如果 key1的哈希值与已经存在的数据的哈希值都不相同,则key1-value1添加成功(entry添加成功);—情况2
    如果 key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,继续比较,调用key1所在类的equals(key2):
    如果 equals返回false:此时key1-value1添加成功;—情况3
    如果 equals返回true:使用value1替换value2.
  • 关于情况2,3:此时key1-value2以链表的形式存储。
  • 扩容问题:当超出临界值(当前数组长度*加载因子(0.75))且当前元素要存放的位置为空,则扩容。默认扩容方式容量为原来的两倍,并将原有的数据复制过来。
    JDK8
  1. new HashMap();底层没有创建一个容量为16的数组;
  2. 底层数组是Node[],不是Entry[];
  3. 首次调用put方法时,才初始化长度为16的数组;
  4. 底层结构:数组+链表+红黑树;
    当数组某一个索引位置上的元素以链表形式存在的数据个数>8,且当前数组长度>=64,此索引位置上的数据采用红黑树存储;(若>8,且不为空,<64,则扩容)
  5. 一些常量:
  • DEFAULT_INITIAL_CAPACITY:默认容量16;
  • DEFAULT_LOAD_FACTOR:默认加载因子:0.75;
  • threshold:扩容的临界值:容量*加载因子(16*0.75);
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值8,转化为红黑树;
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时,最小的hash表容量64

LinkedHashMap

  • 保证在遍历map元素时,可以按照添加的顺序实现遍历。在原有的底层结构基础上,添加了一对引用,指向前一个和后一个元素。对于频繁的遍历操作,此类的执行效率高于HashMap。
  • 底层数据结构:
static class Entry<K,V> extends HashMap.Node<K,V>{
	ENtry<K,V> before,after;//能够记录前一个\后一个元素
	Entry<int hash,K key, V value,Node<K,V> next>{
		super(hash,key,value,next);
	}
}

TreeMap

保证按照添加的key-value对进行排序,实现排序遍历;考虑key的自然排序或者订制排序,底层使用红黑树实现。

Hashtable

作为古老的实现类;线程安全,效率低;不能存储为null的数据。

Properties

常用来处理配置文件,k-v都是String类型。

PS:

  • 感谢尚硅谷宋红康老师的讲解。
  • 个人学习理解所用,如有误或者补充请下方留言,谢谢~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值