[JavaSE]集合学习小结

本文深入解析Java集合框架,包括Collection、List、Set、Map等核心接口及其实现类的特性与使用方法,如ArrayList、LinkedList、HashSet、HashMap等,探讨它们的内部机制、优缺点及适用场景。
摘要由CSDN通过智能技术生成

集合

也可以叫做容器,可以容纳其他类型的数据。

所有的集合类和接口都在java.util包中

集合中存储的是对象的内存地址。本篇中基本上只归纳了一些比较常用的集合类,其他的可以通过这些扩展,为了记录下学习过程而归纳至此。

集合结构图(常用)

在这里插入图片描述

Collection接口中的方法

boolean add(E e)

向集合中添加一个元素,如果因为调用这个方法集合中元素发生了改变,则返回true。在一些集合中如果要添加的元素不允许重复并且已经存在,则返回false。

int size()

返回集合中元素的个数,如果这个集合包含的元素个数超出了Integer.MAX_VALUE,则返回Integer.MAX_VALUE。

void clear()

此方法会将集合中的所有元素删除(可选择的操作),调用这个方法后集合将会变成空的。

如果这个集合不支持清空的操作,会抛出UnsupportedOperationException异常。

boolean contains(Object o)

如果集合中包含指定的元素,则返回true。更正规地说,当且仅当集合中存在一个元素e使得满足Object.equals(o, e)这个条件时返回true。

boolean remove(Object o)

==在指定元素存在的前提下,删除集合中的这个元素。(可选择的操作)==remove的底层也调用了equals方法。

如果指定元素的类型与集合不匹配,则会抛出ClassCastException类型转换异常。

如果指定元素是null并且集合不允许元素为空,则会抛出NullPointerException空指针异常。

如果删除操作在当前集合不被允许,则会抛出UnsupportedOperationException异常。

boolean isEmpty()

如果当前集合不存在任何元素,则返回true。

Iterator

boolean hasNext()

如果在迭代时有更多的元素,则返回true。换句话说,当next()返回的是一个元素而不是抛出一个异常的时候,返回true。

E next()

返回迭代中的下一个元素。

集合的结构如果发生改变,迭代器必须重新获取。如果迭代过程中出现更改集合结构的操作,则会产生ConcurrentModificationException异常。但是可以通过使用迭代器的remove方法删除集合的元素。

原理:

获取迭代器对象后,迭代器用来遍历集合,此时迭代器对集合的状态拍了一个“快照”。迭代器迭代时会通过对比“快照”和原始集合中的状态是否一致,如果原始集合与快照中的集合状态不匹配,则会抛出异常 ;但是使用迭代器的remove方法则会同时删除“快照”中的元素和原始集合中的元素。

用“for each”循环可以很好的代替带有迭代器的循环,它可以处理任何实现了Iterable接口的对象。

List接口

List的特点:

有序,可重复,即存储元素的顺序与取出元素的顺序一致,并且元素可以重复。

List中的方法(特有的、常用的):

void add(int index, E element)

在指定的位置上添加一个指定的元素。将当前处于该位置的元素(如果有的话)和随后的元素向右移动(它们的下表都加一)。效率较低

E get(int index)

返回在List中指定索引上的元素。

int indexOf(Object o)

返回指定元素在List中第一出现的索引值,否则当List不包含指定元素时返回-1。更正规地说,返回满足Object.equals(o, get(i))条件的最小的索引i,否则没有这样的索引时返回-1。

int lastIndexOf(Object o)

返回指定元素在List中最后一次出现的索引值。

E remove(int index)

删除List中指定位置上的元素(可选择的操作)。向左移动其后面的所有元素(将它们的索引值减一)。返回值为在指定位置上被删除的元素。

E set(int index, E element)

将指定元素把List中指定位置上的元素替换掉(可选择的操作)。返回值为被替换的元素。

使用Collections集合工具类的sort()对List中的元素进行排序时,该元素的必须实现Comparable接口。

ArrayList

默认初始容量为10

扩容就是将原始容量变为其1.5倍。(oldCapacity >> 1)

优点:

检索数据时效率较高,由于底层采用的数据结构为数组,数组是一串连续的内存地址。

缺点:

增加或删除元素的时候需要移动其他元素,效率较低。线程不安全。

注意: 因为扩容涉及到内存申请和数据迁移,是比较耗时的,所以如果实先能确定需要存储的数据大小,最好在创建ArrayList的时候事先指定数据大小。

LinkedList

无初始容量。底层采用的数据结构为双向链表

优点:

增删操作效率比较高。

缺点:

查询操作效率较低,因为链表中的元素在空间存储上的内存地址并不连续。

Vector

初始容量为10,扩容机制为扩大为原来的两倍。线程安全,但很少使用了。

线程不安全变成线程安全

使用java.util.Collections类中的方法

例:

public class Example{
    public static void main(String[] args){
        List list = new ArrayList();
        
       	Collections.synchronizedList(list);
        
        list.add("111");
        list.add("222");
        list.add("333");
    }
}

Set

无序,不可重复。不允许增加重复的元素,存储和取出元素的顺序不一致。

TreeSet

特点:TreeSet是一个有序集合。

放在TreeSet中元素如果是自定义的类,那么必须要实现Comparable接口,或者在构造集时必须提供一个Comparator。

比较器的选择:

当比较规则固定,实现Comparable接口。

当比较规则多变,需要频繁切换,则选择使用Comparator接口。(其满足OCP原则)

Map接口

结构:
在这里插入图片描述

存放在Map集合中的元素是以key,value的键值对形式存在的。键是唯一的,并且不能对同一个键存放两个值。如果同一个键增加两个值,那么第二个值会取代上一个。

Map接口中的常用方法:

boolean containsKey(Object key)

如果map中包含指定key,则返回true。更正规地说,当且仅当这个map中包含一个键k它满足Object.equals(key, k)的条件,则返回true。

boolean containsValue(Object value)

如果map中有一个或多个键映射指定值,则返回true。更正规地说,当且仅当这个map中至少包含一个映射到的值v满足Object.equals(value, v)的条件则返回true。

Map集合的遍历:

1、通过keySet()方法将Map转换为只有key的Set集合

(1)再通过迭代器的方法遍历所有的key获取对应的value。

(2)增强for

Map<Integer, String> map = new HashMap<>();
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");

Set<Integer> keys = map.keySet();
for(Integer key: keys){
    System.out.println(key + "=" + map.get(key));
}

2、通过entrySet()方法将map转换为set集合。

(1)迭代器

Set<Map.Entry<Integer, String>> set = map.entrySet();
Interator<Map.Entry<Integer,String>> it = set.iterator();
while(it.hasNext()){
    Map.Entry<Integer,String> node = it.next();
    Integer key = node.getKey();
    String value = node.getValue();
   
}

(2)增强for

for(var entry : set){	//这里可以使用var来代替Map.Entry
    System.out.println("key=" + entry.getKey() + ", value=" + entry.getValue);
}

3、forEach()+Lambda表达式

map.forEach(k,v) -> {
    System.out.println("key=" + k + ", value=" + v);
}

HashMap

无序,存储与取出的顺序不相同;不可重复,存储的数据不能重复。

底层数据结构为哈希表,哈希表又称为散列表,是由数组和单向链表的组合形成的数据结构。

Node<K,V> [] table;

数组中每个元素都是一个Node,其中包括:

final int hash; hash值,通过哈希函数计算得出,可以将其转化为下标。

final K key; 存储在map集合中的键

V value; 存储在map集合中的值

Node<K,V> next; 下一个节点的内存地址

存取原理:

1、put(k, v)

第一步:先将key,value封装到一个node节点中。

第二步:底层调用hashCode()计算hash的值,并通过哈希函数的算法将hash值转化为数组下标,如果下标位置上没有任何元素,就把Node添加到这里;如果下标位置上有链表,会用指定key与链表上的节点中的key进行比对,如果相同,则将value覆盖,如果不同,就将这个新节点添加在这个链表的末尾。

2、get(k)

通过hashCode()方法计算出指定key对应的hash值,再通过哈希算法将其转化为数组下标,然后通过数组下标找到哈希表中数组对应的位置,如果这个位置上什么都没有,则返回null;如果有单向链表,再通过equals方法对比这个下标所在的位置上的链表中的所有节点的key值,如果所有都返回false,则返回null,如果指定key值与某个节点的key通过equals方法返回true,则将这个节点的value值返回。

综上,注意放在HashMap中key部分的元素和HashSet中的元素,要同时重写hashCode()和equals()。

初始化容量

HashMap的初始化容量为16,指定容量时必须是2的倍数,这是因为达到散列均匀同时为了提高HashMap的存取效率。默认加载因子是0.75。

​ 默认加载因子是指 当HashMap集合底层哈希表中的数组容量达到75%时,数组开始扩容。

JDK8之后,HashMap中单链表的长度大于8时,会将其改为红黑树的数据结构,小于6的时候会变回单向链表。为了提高检索效率。

集合之间的转换

Set<String> set = new HashSet<>();

List<String> list = new ArrayList<>(set);

本篇中基本上只归纳了一些比较常用的集合类,其他的可以通过这些扩展,为了记录下学习过程而归纳至此,继续努力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值