[Java基础篇]对Java中的集合相关知识点的剖析

一、了解一些集合类的基本概念

我们以前都已经学过了数组了,我们来回忆以下:数组一旦初始化就指定看数组长度,如果数组需要保存数量变化的数据,数组就显得无能为力了。而且数组也无法保存具有映射关系的数据。如:成绩表:语文-79。
为了保存数量不确定的数据,以及保存具有映射关系的数据(关联数组),Java提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。Java所有的集合类都位于java.util包下,提供了一个表示和操作对象集合的统一框架,包含大量集合接口,以及这些接口的实现类和操作它们的算法。
集合类和数组在保存的数据元素上面的不同:数组元素既可以是基本类型,也可以是对象(实际上保存的是对象引用变量)。二集合里只能保存对象(实际上只是保存对象的引用变量,但习惯认为集合里保存的是对象)。

1.1 Java集合框架的接口

在这里插入图片描述

1.2 Java库中的具体集合

集合类型 描述
ArrayList 一种可以动态增长和缩减的索引序列
LinkedList 一种可以在任何位置进行高效地插入和删除操作的有序序列
ArrayDeque 一种循环数组实现的双端队列
HashSet 一种没有重复元素的无序集合
TreeSet 一种有序集
EnumSet 一种包含枚举类型值的集
LinkedHashSet 一种可以记住元素插入次序的集
PriorityQueue 一种允许高效删除最小元素的集合
HashMap 一种存储键/值关联的数据结构
TreeMap 一种键值有序排列的映射表
EnumMap 一种键值属于枚举类型的映射表
LinkedHashMap 一种记住键/值项添加次序的映射表
WeakHashMap 一种其值无用武之地后可以被垃圾回收期回收的映射表
IdentityHashMap 一种用==而不是用equals比较键值的映射表

在这里插入图片描述
在这里插入图片描述
在上面的图中我们可以看到很多以“Abstract”开头的容器,其实它们只是部分实现某个特定接口的简单工具而已。如:我们如果要制作自己的Set的话,一般不会直接继承Set接口,然后实现所有的方法。而是应该继承AbstractSet,只为自己的新类作最必要的工作。不过,容器类类库已经包含足够的功能来满足你的需要了。所以,对我们而言,可以忽略那些以“Abstract”开头的类。
*☞ 注意:所有的Collection都能通过iterator()方法生成Iterator。

☞ 容器的缺点:未知类型
容器只保存Object型的引用,这是所有类的基类,因此容器可以保存任何类型的对象。不过:

  1. 因为在你将对象的引用加入容器就丢失了类型的信息,所以对于添加容器的对象没有类型限制,即使你刻意保持容器的类型。例如类型“猫”的容器,别人是可以轻易将“狗”放入容器

  2. 因为丢失了类型信息,容器只知道它保存的是Object类型的引用。在使用容器中的元素前必须要做类型转换操作

1.3 迭代器

任何容器都必须实现有方法可以将东西方法放进去,然后有方法将东西取出来。毕竟,存放事物是容器最基本的工作。对于ArrayListadd() 是插入对象的方法,而get() 是取出元素的方法之一。但是如果原本是使用ArrayList,后来考虑到容器的特点,想换用Set 怎么做?难道重写代码吗?
当然不是,迭代器就是更好的实现这种目的。迭代器是一个对象,它的工作是遍历并选择序列中的对象。迭代器通常被称为“轻量值”对象:创建它的代价小。因此经常可以见到对迭代器有些奇怪的限制。

如Java的Iterator就是迭代器受限制的例子,它只能用来:
☞ 使用方法iterator() 要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列中的下一个元素。
☞ 使用next() 获得序列中的下一个元素。
☞ 使用hasNext() 检查序列中是否还有元素。
☞ 使用remove() 将上一次返回的元素从迭代器中移除。

///创建一个通用的打印方法
public class Main {   
    static void printAll(Iterator e) { 
      while(e.hasNext())
      Syste.out.println(e.next()); 
       } 
   } 

二、 常见的集合类

在这里插入图片描述

2.1 Collection详解

此图摘取于:Java集合详解
在这里插入图片描述
Collection接口是List、Set接口和Queue接口的父接口。Collection是集合类(Map除外)的根接口。
Collection提供了如下方法对List集合元素进行排序:

1.void reverse(List list): 对指定 List 集合元素进行逆向排序。
2.void shuffle(List list): 对 List 集合元素进行随机排序(shuffle 方法模拟了“洗牌”动作)。
3.void sort(List list): 根据元素的自然顺序对指定 List 集合的元素按升序进行排序。
4.void sort(List list, Comparator c): 根据指定 Comparator 产生的顺序对 List 集合元素进行排序。
5.void swap(List list, int i, int j): 将指定 List 集合中的 i 处元素和 j 处元素进行交换
6.void rotate(List list, int distance): 当 distance 为正数时,将 list 集合的后 distance 个元素“整体”移到前面;当 distance 为负数时,将 list 集合的前 distance 个元素“整体”移到后面。该方法不会改变集合的长度。

Collection 还提供了如下常用的用于查找、替换集合元素的方法:

1.int binarySearch(List list, Object key): 使用二分搜索法搜索指定的 List 集合,以获得指定对象在 List 集合中的索引。保证 List 中的元素已经处于有序状态。
2.Object max(Collection coll): 根据元素的自然顺序,返回给定集合中的最大元素
3.Object max(Collection coll, Comparator comp): 根据 Comparator 指定的顺序,返回给定集合中的最大元素。
4.Object min(Collection coll): 根据元素的自然顺序,返回给定集合中的最小元素。
5.Object min(Collection coll, Comparator comp): 根据 Comparator 指定的顺序,返回给定集合中的最小元素。
6.void fill(List list, Object obj): 使用指定元素 obj 替换指定 List 集合中的所有元素
7.int frequency(Collection c, Object o): 返回指定集合中指定元素的出现次数
8.int indexOfSubList(List source, List target): 返回子 List 对象在父 List 对象中第一次出现的位置索引;如果父 List 中没有出现这样的子 List,则返回 -1。
9.int lastIndexOfSubList(List source, List target): 返回子 List 对象在父 List 对象中最后一次出现的位置索引;如果父 List 中没有岀现这样的子 List,则返回 -1。
10.boolean replaceAll(List list, Object oldVal, Object newVal): 使用一个新值 newVal 替换 List 对象的所有旧值 oldVal。

了解指定的排序规则:
Java提供了只包含一个compareTo()方法的Comparable接口。包含compare()equals() 两个方法的Comparator接口。

Comparable和Comparator两个接口的区别:
Comparable(通过实体对象来调用): 强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
Comparator(比较器,可以直接执行): 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序

2.1.1 List接口

List接口中元素的存放特点是:元素存放有序,同一元素可重复,带索引的集合。List接口存在三个实现类:ArrayList、LinkedList和Vector

☞ ArrayList类

ArrayList类实现了可变数组的大小,存储在内的数据称为元素,它还提供了快速基于索引访问元素的方式。元素增删慢,查找快,ArrayList最常用来查询数据、遍历数据。
ArrayList类除了包含Collection接口中的所有方法之外,还包括以下方法:
在这里插入图片描述
☞ LinkedList类

LinkedList类采用链表结构保存对象,这种结构的有点是便于向集合中插入或者删除元素。需要频繁向集合中插入和删除元素时,使用LinkedList类比ArrayList类效果高,但是Linkedlist类随机访问元素的速度则相对较慢。这里的随机访问是指检索集合中特定索引位置的元素。
LinkedList类 除了包含 Collection 接口和 List 接口中的所有方法之外,还包含以下方法。
在这里插入图片描述
☞ Vector类

与ArrayList类似,但属于强同步类(线程安全)。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。越安全,效率越低。(所以Java中很少使用Vector类)

☞ ArrayList、LinkedList和Vector之间的区别:

ArrayList和LinkedList:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数结构。
2.对于随机访问get和set,ArrayList优于LinkedList,由于LinkedList要移动指针
3.对于新增和删除操作的add和remove,LinkedList优于ArrayList,由于ArrayList要移动数据。(但是如果只对单条数据的插入或删除,ArrayList优于LinkedList)

ArrayList和Vector的区别:
1.同步性:Vector是线程性同步,所以它是线程安全的,而ArrayList是线程异步的,是不安全。
2.数据增长:从内部实现机制来讲,ArrayList和Vector都是使用数组来控制集合的对象,如果集合中的元素的数目大于目前集合数组的长度时,Vector增长率为目前数组长度的100%,而ArrayList增长率为,目前数组长度的50%。所以如果在集合中数据量比较大的数据,用Vector有一定的优势。

2.1.2 Set接口

Set集合类似于一个罐子,程序可以依次把多个对象“丢进”Set集合,而Set集合通常不能记住元素的添加顺序。也就是Set集合中的对象不按特定的方式排序,只是简单地把对象加入集合。Set集合中不能包含重复的对象(如果向Set集合中添加两个相同的元素,则后添加的会覆盖前面添加的元素,即在Set集合中不会出现相同的元素),并且最多只允许包含一个null元素。

Set实现了Collection接口,实际上Set就是Collection,只是行为不同而已。Set于Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。它主要有两个主要的实现类:HashSetTreeSet

☞ HashSet类

HashSet是按照Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。保证元素的唯一性方式依赖于:hashCodeequals方法。java.util.HashSet底层的实现其实是一个java.util.HashMap支持。

HashSet具有以下特点:
1.不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
2.HashSet不是同步的(线程不安全的),如果多个线程同时访问或修改一个HashSet,则必须通过代码来保持同步。
3.集合元素值可以是null。

我们都知道HashSet保证了元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序的话:
在这里插入图片描述
☞ TreeSet类

TreeSet类同时实现Set接口和SortedSet接口。SortedSet接口是Set接口的子接口,可以实现对集合进行自然排序(升序),因此使用TreeSet类实现的Set接口默认情况下是自然排序的。TreeSet只能实现了Comparable接口的类对象进行排序,因为Comparable接口中有一个**compareTo(Object o)**方法用于比较两个对象的大小。因为Comparable接口中有一个compareTo(Object o)方法用于比较两个对象的大小。例如a.compareTo(b),如果a==b,则该方法返回0;如果a>b,返回大于0的值;如果a<b,则该方法返回小于0的值。
Tree类除了实现Collection接口的所有方法之外,还实现以下方法:
在这里插入图片描述

HashSet类和TreeSet的区别:

实现方式 数据是否有序 是否可以放入null值
HashSet 哈希表实现 HashSet中的数据是无序的 可以放入null,但只能放入一个null
TreeSet 二叉树实现 TreeSet的数据是自动排好序的 不允许放入null值

2.2 Map详解

此图摘取于:Java集合详解
在这里插入图片描述
Map是一种键-值对集合,Map集合中的每一个元素都包含一个键(key)对象和一个值(value)对象。用于保存具有映射关系的数据。(键不允许重复,但允许值重复)
Map中的key和value之间存在的单向一对一关系,即通过指定的key,总能找到唯一的、确定的value。从Map中取出数据时,只要给出指定的key,就可以取出对应的value。
Map接口主要有两个实现类:HashMap类和TreeMap类。其中,HashMap类按哈希算法来存取键对象,而TreeMap类可以对键对象进行排序。

☞ HashMap类
HashMap是一个最常用的Map,它根据的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

HashMap的特点:
1.允许一条记录键为NULL;允许多条记录的值为NULL
2.不支持线程同步

Hashable: 线程安全的,不允许NULL的键或值。
LinkedHashMap: 保留数据的存入顺序(和LinkedHastSet用法类似)

TreeMap类
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以用指定排序的比较器。
TreeMap 类的使用方法与 HashMap 类相同,唯一不同的是 TreeMap 类可以对键对象进行排序:
在这里插入图片描述
其他一些方法:isEmpty() 判断Map是否为空、size() 返回键值对个数、Collection values() 返回Map里所有value组成的Collection等。
Entry键值对对象

我们已经知道,Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map中是一一对应关系,这一对对象又称做Map中的一个Entry(项)。Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

既然Entry表示了一对键和值,那么也同样提供了获取对应键和对应值得方法:
public K getKey(): 获取Entry对象中的键。public V getValue(): 获取Entry对象中的值。
在Map集合中也提供了获取所有Entry对象的方法:
**public Set <Map.Entry<K,V>> entrySet()😗*获取到Map集合中所有的键值对对象的集合(Set集合)。

三、参考资料

1.C语言中文网
2.Java集合详解
3.https://zhidao.baidu.com/question/85559012.html
4.《Java编程思想》
5.《Java核心技术卷Ⅰ》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章