最详细总结Java''集合类''(面试必备)!

集合

1.什么是集合?

集合可以看做一种容器。集合中的"对象"(准确的说是引用),很容易从集合中取出,也很容易存放到里面。
java中提供了不同的集合类,它们有着不同的存储方式,并提供相应方法,以便用户对集合进行遍历,删除等操作。

注意:
集合不能直接存储基本数据类型,另外集合也不能直接存储java对象。
集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)


2.集合和数组的区别?

数组:长度固定,存放基本类型数据
集合:长度可变,存放对象引用


3.主要集合概述?

1.List:有序可重复
2.Set:无序不可重复
3.Map:无序键值对形式。键不可重复值可重复。(如:身份证号—姓名)
(三个都是接口,三个接口下分别有不同的集合类,其中同时List和Set一起继承了Collection接口)

特别注意:有序:指的是放进去的顺序和取出来的顺序一样,而不是从小到大"排序"。
如放进去的顺序是"01",“02”,“03”,取出来的顺序也是"01",“02”,“03”。


4.常用集合类的继承关系图?

通过常用集合类的继承关系图,可以清楚的了解它们之间的关系,了解了总体关系在进行逐个分析。

在这里插入图片描述
在这里插入图片描述


5.Collection中的常用方法?

Collection接口下有ListSet两个接口
常用方法:
1.add(E e):指定对象添加到集合。
2.remove(Object o):指定对象移除。
3.isEmpty():判断当前集合是否为空。
4.iterator():返回在此Collection的元素上进行迭代的迭代器,用于遍历集合中的元素。
5.size():获取集合中元素的个数,返回int值。
6.contains(Object o) :如果此 collection 包含指定的元素,则返回 true。
7.clear() :移除此 collection 中的所有元素(可选操作)。


6.Iterator接口?

迭代器原理:迭代器就像一个箭头,指向集合中的元素,迭代器以下方法:
1.hasNext() :判断是否有下一个元素。(就像箭头指向元素,看能不能还有下一个元素让箭头指。)
2.next() :有下一个元素的话,通过此方法获取。(hasNext返回true,就调用next方法,让箭头指向下一个元素)
3.remove():从底层集合中移除此迭代器返回的最后一个元素(可选操作),每次调用next()时,只能调用此方法一次。(与集合的remove方法区分开)

在这里插入图片描述

5.4中提到Collection中有iterator()方法,用于遍历,我们来实现一下。
实现步骤如图:

在这里插入图片描述

特别注意:
1.代码中自动装箱了,Iterator调用next返回的其实是Object
2.迭代器的创建必须在元素操作后(图中13行代码必须在9,10,11后),因为创建迭代器相当于给集合中的元素"拍照片",加入了三个元素,创建了迭代器,遍历出的也是这三个元素。但是创建迭代器之后,又有了新的元素操作,但是迭代器"照片"只会有它创建之前的。迭代器的"照片"内容并不会有改变,所以会出错(ConcurrentModificationException)。
如:集合的remove方法如果出现在创建迭代器之后就会有错误,但是,迭代器对象调方法没事,如iterator的remove方法,因为它相当于迭代器自己的操作,改变后这个"相片"又重新拍照了,所以可以。
3.代码中< String >为泛型,意思就是规定了只能放String类元素。


7.foreach遍历?

除了迭代器遍历还有一种增强for的遍历方法,语法:for(类型 名称:集合对象){ 语句 }
某些时候这样遍历效率更高,但是也存在它的缺点,例如不能在增强循环里动态的删除集合内容。不能获取下标等。
在这里插入图片描述


8.List集合?

特点:有序可重复
常用方法:
1.void add(int index, Object element):根据索引添加元素,索引从0开始。
2.Object set(int index, Object element):根据索引修改元素。
3.Object get(int index):通过索引获取元素。
4.int indexOf(Object o):通过元素获取索引。
5.int lastIndexOf(Object o):返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1。
6.int lastIndexOf(Object o):元素最后一次出现的索引位置。
7.Object remove(int index):根据索引删除元素。
(元素可以是null)
在这里插入图片描述


8.1ArrayList?

底层实现数据结构:数组(可变)。
优点:检索速度快,根据索引位置对集合进行快速的访问,末尾添加元素快。
缺点:插入或删除的速度较慢。(想想插进一个新的就要把后面的都移动位置,所以慢)


8.2List中的LinkedList?

底层实现数据结构:双向链表
优点:插入或删除元素速度快(不涉及元素的大量位移)。
缺点:检索,查询速度慢(需要从头开始遍历)

线程不安全:
怎么得到一个线程安全的List:Collections.synchronizedList(list);

在这里插入图片描述


8.3Vector?

与ArrayList相似,线程安全,但效率很低,通常不用。

9.Set集合?

特点:无序不可重复(存进去的元素和取出来的元素顺序不同)
元素可以为null

在这里插入图片描述


9.1HashSet?

底层实现数据结构:哈希表
并且实际上,它是相当于存在了HashMap键值对中的key,下文有HashMap的讲解,会了HashMap就会了HashSet。

9.2SortedSet?

继承Set接口,TreeSet继承它。
特点:无序不可重复,可以自动排序(大小顺序排列)

9.2.1TreeSet?

继承于SortedSet
底层实现数据结构:二叉树:左节点比右节点小,采用中序遍历(左根右)输出顺序正好是从小到大顺序。
无序不可重复的,但是存储的元素可以自动按照大小顺序排序!
对自定义的类型来说,TreeMap不能排序,因为没有指定对象之间的比较规则。谁大谁小并没有说明。
会出现异常:是因为没有实现java.lang.Comparable接口。

自定义类型实现自动排序的两种方法:
1.放在TreeSet集合中的元素需要实现java.lang.Comparable接口。
在这里插入图片描述
观察源代码分析:
k.compareTo(t.key):后进来的元素和根元素比较。
相当于:c2.compareTo(c1.key)。
相当于:this.age和c.age比较。
相当于:也就是20和32比较
相当于:20-32:小于0:20放在32左面。

return this.age(20:后进来的)-c.age(32:根):
如果小于0:this.age<c.age (20<32):20放在32二叉树左节点(左小右大)
如果大于0:this.age>c.age (20>32(错误)):放在二叉树右节点
0(20=32):相同:不存储(无序不可重复)
在这里插入图片描述

2.使用比较器的方式。(两种)
1.在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。

在这里插入图片描述
源码分析:
cpr.compare(key,t.key):
相当于:compare(后加进来的,根)
相当于:compare(o1,o2)
相当于:compare(800,1000)
相当于:o1.age-o2.age
相当于:800-1000:小于0,800放在1000的左面。

在这里插入图片描述

2.匿名内部类方法:
在这里插入图片描述

结论:
放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:
第一种:放在集合中的元素实现java.lang.Comparable接口。
第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
Comparable和Comparator怎么选择呢?
当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议实现Comparable接口
如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口
Comparator接口的设计符合OCP原则。


10.Map?

特点:无序不可重复。(key不可重复value可重复)
key,value键值对( 不能有相同的key,key可以为null,只能有一个,一个key只能映射一个value)
常用方法:
1.put(K key ,V value):添加指定的映射关系。
2.containsKey(Object key):如果此映射包含指定key的映射关系,返回true。
3.containsValue(Object value):如果此映射将一个或多个key映射到返回值,返回true。
4.get(Object key):如果存在指定的key对象,返回该对象的对应值,否则返回null。
5.keySet():返回所有key对象形成一个Set集合。
6.values():返回所有值对象形成的Collection集合。
7.int size() 获取Map集合中键值对的个数。
8. V remove(Object key) 通过key删除键值对
9. boolean containsKey(Object key): 判断Map中是否包含某个key。(底层调用equals,如果自定义类型要重写了equals方法)
10. boolean containsValue(Object value) :判断Map中是否包含某个value。 (底层调用equals,如果自定义类型要重写了equals方法)
11. Set<Map.Entry<K,V>> entrySet():将Map集合转换成Set集合
在这里插入图片描述


10.1HashMap?

特点:无序不可重复。(key不可重复,value可重复)
key,value键值对( 不能有相同的key,key可以为null,只能有一个。一个key只能映射一个value)。

HashMap遍历的两种方法:
1.第一种:获取所有key,遍历每个key,通过key获取value.
在这里插入图片描述

2.第二种:Set<Map.Entry<K,V>> entrySet()方法,把Map集合直接全部转换成Set集合。
在这里插入图片描述

底层实现的数据结构:
哈希表:数组中每一个元素是一个单向链表
在这里插入图片描述

map.put(key,value)实现原理:
1.把k和v封装在Node对象中。
2.底层调用k的hasCode()方法得出哈希值。
3.通过哈希算法/函数,将哈希值转换成数组下标,下标位置如果没有元素,就把这个Node添加到这个位置上。
4.如果下标对应的位置上有链表了,那就用k和链表上的每一个k进行equals比较。
5.如果都为false,添加到这个链表上的末尾。
6.如果返回true,那么就把重复的那个覆盖上。
(一个单向链表上Node的k值都是不一样的)
(理论上,一个单向链表上Node的hash值都是一样的,因为下标一样。)
特别注意:hash如果不一样,通过哈希算法却得到了一样的下标,也是有可能的,这是因为"哈希碰撞"原理,
就如同7/3取余=1,4/3取余也=1一样。hash不一样,通过哈希算法也可以得到一样的下标。

v=map.get(k)实现原理:
1.调用k得hasCode()得到哈希值,通过哈希算法得到数组下标。
2.在这个数组下标处如果没有单向链表,返回null。
3.如果有在这个数组下标的单向链表中和每一个Node的k比较,找到一样的那个,输出这个k对应的value。
4.如果没有找到k相同的,则null。

重点:不管是存还是取,都是先调用hashCode(),再调用equals()。
equals可能调用也可能没有调用,因为如果存或者取的时候哈希值经过哈希算法转换成数组下标,数组下标位置为null时,代表没有元素,
既然没有元素,所以放的时候不用比较,直接放入。取的时候也没有元素可以取,所以不用equals比较。
方法重写:equals方法重写了,hashCode方法必须重写。equals比较相同时,就说明在同一个链表上,所以hash值一样。

哈希表的随即增删和查询效率都可以,这是因为数组中有单向链表的原因,增删通过链表完成,查询也不用全部遍历。


10.2Hashtable?

Hashtable的key和value都是不能为null的。
Hashtable方法都带有synchronized:线程安全的。
线程安全有其它的方案,这个Hashtable对线程的处理
导致效率较低,使用较少了。


10.2.1Properties?

继承Hashtable,Properties的key和value都是String类型。
Properties被称为属性类对象。
Properties是线程安全的。


10.3TreeMap?

与HashSet完全类似,TreeSet里面绝大部分方法都市直接调用TreeMap方法来实现的。
无序不可重复的,但是存储的元素可以自动按照大小顺序排序!
TreeMap集合底层是一个二叉树。(红黑树)。
运行速度都要比Hash集合慢
TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)
TreeSet中不能有重复对象,而TreeMap中可以存在
TreeMap的底层采用红黑树的实现,完成数据有序的插入,排序。
TreeMap不允许键(key)对象是null。


11.Collections?

java.util.Collections 集合工具类,方便集合的操作。
通过**Collections.synchronizedList(list);变成线程安全的
通过
Collections.sort(list);**可进行排序

1.将ArrayList变成线程安全的,并排序:在这里插入图片描述

2.对List集合排序,List集合中的元素需要实现从Comparable接口:

在这里插入图片描述

3.对Set集合进行排序,先将Set集合转为List集合,再用Collections.sort()进行排序:

在这里插入图片描述


12.各个集合类的初始化容量和扩容总结?

1.ArrayList:初始化容量:10 每次扩容:1.5倍
2.LinkedList:初始化容量:0
3.Vector:初始化容量:10 每次扩容:2倍
4.HashMap:初始化容量:16 (最好是2的倍数) 每次到达0.75时扩容:2倍
5.HashSet:初始化容量:16 (最好是2的倍数) 每次到达0.75时扩容:2倍
6.HashTable:初始化容量:11 每次扩容:2倍+1

注意:Set< String > set = new HashSet<>(100);
如这种在定义时就规定了初始化容量的操作,将不会进行扩容,直接就是定义的大小。


如果对你有帮助的话,可以点赞,收藏,关注我~ 谢谢~

发布了19 篇原创文章 · 获赞 28 · 访问量 1237

猜你喜欢

转载自blog.csdn.net/weixin_44307737/article/details/105637054