Java 基础 - 集合框架

554 阅读8分钟

往期推荐

集合概述

集合的由来

通常,我们的程序需要根据程序运行时才知道创建多少个对象。但若非程序运行,程序开发阶段,我们根本不知道到底需要多少个数量的对象,甚至不知道它的准确类型。为了满足这些常规的编程需要,我们要求能在任何时候,任何地点创建任意数量的对象,而这些对象用什么来容纳呢?我们首先想到了数组,但是数组只能放统一类型的数据,而且其长度是固定的,那怎么办呢?集合便应运而生了!

集合是什么?

Java集合类存放于 java.util 包中,是一个用来存放对象的容器

注意:

① 集合只能存放对象。比如你存一个int 型数据放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。

② 集合存放的是多个对象的引用,对象本身还是放在堆内存中。

③ 集合可以存放不同类型,不限数量的数据类型。

集合和数组的区别

  • 数组存放的类型只能是基本数据类型或引用数据类型,集合中存放的数据类型只能是引用数据类型
  • 数组是静态的,一个数组实例具有固定的大小,一旦创建了不能改变容量。而集合是可以动态扩展容量,可以根据需要动态改变大小。
  • 初始化数组时需要声明存放在数组中的数据类型,而集合可以声明或不声明,当不声明时默认为Object类型,Object是Java中的超类,这就意味着一个集合中可以存放混合类型的数据(既存放String类型的数据又存放Integer类型的数据)

集合框架的基础接口

  • Collection:是集合框架的基础接口之一,在Java中不提供该接口的任何直接实现。

  • List:是一个可以包含重复元素的集合。每个元素都有对应的顺序索引,实现类主要有ArrayListLinkedList等。

  • Set:是一个不能包含重复元素的集合,并且元素没有特定顺序。

  • Map:是用于保存具有映射关系的键值对数据,提供key(键)到value(值)的映射。一个Map不能包含重复的key,每个key最多映射到一个value。

  • Queue:是数据结构中队列结构的实现。在queue中元素具有隐含的顺序,且每个queue都有一个head元素

  • Iterable:是一个迭代器接口,使用该接口可以从集合中每次返回其中的一个元素

集合框架常用集合类

77.png

Collection接口

Collection接口是Set,Queue,List的父接口。

Collection接口中定义了多种方法可供其子类进行实现,以实现数据操作。

下面是Collection的类结构图:

0003.png

Collections工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。

Collections提供了多个synchronizedXx()方法,把线程不安全的list/Collection/map转换为线程安全0

public class CollectionsTest {
    @Test
    public void test1() {
        List<Integer> list = new ArrayList<>();
        list.add(41);
        list.add(13);
        list.add(55);
        list.add(55);
        //1) reverse(list)方法 反转list中的元素
        Collections.reverse(list); // 对list做修改 没有返回值
        //2) shuffle(list)方法 对list进行随机打乱排列
        Collections.shuffle(list);
        //3) sort(list) 对list进行排序 需要实现compareTo方法
        Collections.sort(list);
        //4) swap(list,i,j) 对list中的i处的元素和j处的进行交换
        Collections.swap(list,0,3);
        //5) max(Collection) 返回Collection中最大的元素(基于compareTo方法)
        //6) min(Collection) 返回Collection中最小的元素(基于compareTo方法)
        //7) frequency(Collection,i) 返回Collection中i出现的次数
        int frequency = Collections.frequency(list, 55);
        //8) copy(list dest,list src) 把src的内容复制到dest中
        // 应该先新建一个带src.size()个数null的一个list
        List<Object> dest = Arrays.asList(new Object[list.size()]);
        Collections.copy(dest,list);
        // 9) 利用synchronizedList(list)方法 将list转换为线程安全的
        List<Integer> list1 = Collections.synchronizedList(list);
    }
}

Collection和Collections的区别

  • java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
  • Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

List接口

实现List接口的集合是有序的、可重复的。

List接口主要有四个实现类: 分别是ArrayListVectorLinkedListCopyOnWriteArrayList

常用方法

1.操作元素

  • get(int index):返回List集合中指定位置的元素。
  • set(int index, Object element):用指定元素替换List集合中指定位置的元素。
  • add(Object element):在List集合的尾部添加指定的元素。该方法是从Collection集合继承过来的。
  • add(int index, Object element):在List集合的指定位置插入指定元素。
  • remove(int index):移除List集合中指定位置的元素。
  • remove(Object element):如果List集合中存在指定元素,则从List集合中移除第一次出现的指定元素。该方法是从Collection集合继承过来的。
  • clear():从List集合中移除所有元素。该方法是从Collection集合继承过来的。

2.判断元素

  • isEmpty():判断List集合中是否有元素,没有返回true,有返回false。该方法是从Collection继承过来的。
  • contains(Object element):判断List集合中是否包含指定元素,包含返回true,不包含返回false。该方法是从Collection集合继承过来的。

3.查询元素

  • indexOf(Object o):从前往后查找List集合元素,返回第一次出现指定元素的索引,如果此列表不包含该元素,则返回-1。
  • lastIndexOf(Object o):从后往前查找List集合元素,返回第一次出现指定元素的索引,如果此列表不包含该元素,则返回-1。

4.其它

  • iterator():返回迭代器(Iterator)对象,迭代器对象用于遍历集合。该方法是从Collection继承过来的。
  • size():返回List集合中的元素数,返回值是int类型。该方法是从Collection集合继承过来的。
  • subList(int fromIndex, int toIndex):返回List集合中指定的 fromIndex(包括 )和 toIndex(不包括)之间的元素集合,返回值为List集合。

遍历集合

集合最常用的操作之一是遍历,遍历就是将集合中的每一个元素取出来,进行操作或计算。

  • 使用for循环遍历:List集合可以使用for循环进行遍历,for循环中有循环变量,通过循环变量可以访问List集合中的元素。
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
  • 使用for-each循环遍历:for-each循环是针对遍历各种类型集合而推出的,笔者推荐使用这种遍历方法。
for (Object o : list) {
    System.out.println(o);
}
  • 使用迭代器遍历:Java提供了多种迭代器,List集合可以使用Iterator和ListIterator迭代器。
//获取迭代器
Iterator iterator = list.iterator();
//判断是否还有元素
while(iterator.hasNext()){
   System.out.println(iterator.next());
}

:使用for-each循环遍历使用迭代器遍历从集合中取出的元素都是Object类型。

ListIterator和Iterator的区别

  • Iterator可以遍历SetList 集合,而ListIterator只能用于遍历List

  • Iterator和ListIterator都可实现删除元素,但是ListIterator可以实现遍历时对元素的修改,用set()方法实现。Iterator仅能遍历,不能修改。

  • Iterator只能单向遍历 [ hasNext()、next()方法)] ,而ListIterator可以双向遍历(向前/后遍历) [ 从后往前 hasPrevious()、previous()方法 ]

  • ListIterator接口继承于Iterator接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

Set接口

常用方法

1.操作元素

  • add(Object element):在Set集合的尾部添加指定的元素。该方法是从Collection集合继承过来的。
  • remove(Object element):如果Set集合中存在指定元素,该方法是从Collection集合继承过来的。
  • clear():从Set集合中移除所有元素。该方法是从Collection集合继承过来的。

2.判断元素

  • isEmpty():判断Set集合中是否有元素,没有返回true,有返回false。该方法是从Collection集合继承过来的
  • contains(Object element):判断Set集合中是否包含指定元素,包含返回true,不包含返回false。该方法是从Collection集合继承过来的。

3.其他

  • iterator():返回迭代器(Iterator)对象,迭代器对象用于遍历集合。该方法是从Collection集合继承过来的。
  • size():返回Set集合中的元素数,返回值是int类型。该方法是从Collection集合继承过来的。

Set和List的区别

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。

  2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变  <实现类有HashSet,TreeSet>

  3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变  <实现类有ArrayList,LinkedList,Vector>  

Map接口

Map(映射)集合表示一种非常复杂的集合,允许按照某个键来访问元素。Map集合是由两个集合构成的,一个是键(key)集合,一个是值(value)集合。键集合是Set类型,因此不能有重复的元素。而值集合是Collection类型,可以有重复的元素。Map集合中的键和值是成对出现的。

常用方法

1.操作元素

  • get(Object key):返回指定键所对应的值;如果Map集合中不包含该键值对,则返回null。
  • put(Object key, Object value):指定键值对添加到集合中。
  • remove(Object key):移除键值对。
  • clear():移除Map集合中所有键值对。

2.判断元素

  • isEmpty():判断Map集合中是否有键值对,没有返回true,有返回false。
  • containsKey(Object key):判断键集合中是否包含指定元素,包含返回true,不包含返回false。
  • containsValue(Object value):判断值集合中是否包含指定元素,包含返回true,不包含返回false。

3.查看集合

  • keySet():返回Map中的所有键集合,返回值是Set类型。
  • values():返回Map中的所有值集合,返回值是Collection类型。
  • size():返回Map集合中键值对数。

Map与Set、List的关系

  1)Map集合与Set集合的关系:如果把Map里的所有key放在一起看,他们就组成了一个Set集合(所有的key没有顺序,key与key之间不能重复),实际上Map确实包含了一个keySet()方法,用户返回Map里所有key组成的Set集合。

  2)Map集合与List集合的关系:如果把Map里的所有value放在一起来看,它们又非常类似于一个List:元素与元素之间可以重复,每个元素可以根据索引来查找,只是Map中索引不再使用整数值,而是以另外一个对象作为索引。

Queue

  Queue用于模拟队列这种数据结构。队列通常是指“先进先出(FIFO)”的容器。队列的头部保存在队列中存放时间最长的元素,尾部保存存放时间最短的元素。新元素插入到队列的尾部,取出元素会返回队列头部的元素。通常,队列不允许随机访问队列中的元素。

PriorityQueue

  优先队列采用堆这种数据结构,元素可以按照任意顺序插, 但是删除的时候总是会删除最小的那个。优先队列主要用于任务调度,当启动新任务时会把优先级最高的任务从队列中删除(习惯上优先级最高的是1)。这里添加的对象(元素)需要实现compareTo方法。

public class PriorityQueueTest {
    @Test
    public void test1() {
        var pq = new PriorityQueue<LocalDate>();
        pq.add(LocalDate.of(2021, 7, 1));
        pq.add(LocalDate.of(2021, 8, 18));
        pq.add(LocalDate.of(2021, 9, 20));
        // 调用remove时会把元素中最小的那个删除掉
        pq.remove();
        System.out.println(pq); //output:[2021-07-01, 2021-09-20]
    }
}

参考资料

[菜鸟教程][Java集合框架]

[ Java学习基础 ][Java的对象容器 -- 集合]

1111.gif