首页 > 技术文章 > Java 集合框架(List,Set,Map)的超详细介绍

Jyh-c 2020-07-27 21:50 原文

写前边:
简单讲了Java集合,区别于其它教程的繁琐。
适合初学者,当然基础不牢也可以复习使用。
集合是一个频繁使用多态的地方,多态掌握好再看集合,
就是各个接口和实现类相对应的关系,复杂的集合关系也就迎刃而解了。

一、集合概述

1.集合的介绍

集合类是Java数据结构的实现。Java的集合类是java.util包中的重要内容,它允许以各种方式将元素分组,并定义了各种使这些元素更容易操作的方法。Java集合类是Java将一些基本的和使用频率极高的基础类进行封装和增强后再以一个类的形式提供。集合类是可以往里面保存多个对象的类,存放的是对象,不同的集合类有不同的功能和特点,适合不同的场合,用以解决一些实际问题。1

2.分类

Java 中的集合分为了两大类,Collection(单列集合)和Map(双列集合)。每个大类下又根据功能的不同做了更加细致的划分。

本文章的结构将按照下图结构进行阐述(仅列出了主要接口和实现类,简化结构,便于理解学习)。
在这里插入图片描述


将按照 由高层次的接口到底层的实现类 顺序介绍集合框架。


二、Collection< E >(单列集合)

<E> 是什么?不懂泛型?那么读之前不妨去看看 ↓ ↓ ↓
Java泛型 → https://blog.csdn.net/weixin_44580492/article/details/107609532

1.Collection接口的使用

介绍

位置:java.util.Collection<E>
主要子接口:List、Set

特有方法

方法信息方法作用
1.boolean add(E e)将给定对象添加到当前集合
2.void clear()清空集合所有元素
3.boolean remove(E e)将给定对象从当前集合删除
4.boolean contains(E e)判断当前集合中是否包含给定的对象
5.boolean isEmpty()判断当前集合是否为空
6.int size()返回集合中元素的个数
7.Object toArray()把集合的元素存储到数组中
8.Iterator<E> iterator()返回在此 collection 的元素上进行迭代的迭代器。

【tips】
上层接口中的方法,底层的接口和实现类都是可以用的


1.boolean add(E e),将给定对象添加到当前集合
添加数据时,一般不使用该方法的返回值(返回值一定是true)。

//创建集合对象
Collection<String> col = new ArrayList<>();
/*
合添加数据
*/
col.add("你好");
col.add("小斑马。");

2.void clear()清空集合所有元素,不删除集合

/*
清空集合所有元素。不删除集合
*/
col.clear();

3.boolean remove(E e),将给定对象从当前集合删除

/*
删除集合中的指定元素
若集合中存在元素,则进行删除并返回true,否则false
 */
boolean bre = col.remove("你好");

4.boolean contains(E e),判断当前集合中是否包含给定的对象

/*
判断集合是都包含某个对象
*/
boolean bco = col.contains("你好");

5.boolean isEmpty(),判断当前集合是否为空

/*
判断集合是否为空
*/
boolean bem = col.isEmpty();

6.int size(),返回集合中元素的个数

/*
返回集合元素个数
*/
int count = col.size();

7.Object toArray(),把集合的元素存储到数组中

/*
集合转换为数组
*/
Object[] obj = col.toArray();

8.Iterator<E> iterator()返回在此 collection 的元素上进行迭代的迭代器。
由于篇幅问题,在另外一篇博客详细介绍了Java集合的迭代器
↓ ↓ ↓ 点下方连接传送 ↓ ↓ ↓
Java迭代器 → https://blog.csdn.net/weixin_44580492/article/details/107609524

2.List集合

介绍

位置:java.util.List<E>
主要实现类:ArrayListLinkedListVector
特征

  • 1.有序,存储与取出元素的顺序是一致的
  • 2.有索引(含有带索引的方法)
  • 3.允许重复的元素(区分Set集合)

特有方法
List集合特有的方法是带索引的方法。

方法信息方法作用
1.void add(int index, E element)在列表的指定位置插入指定元素(可选操作)。
2.E get(int index)返回列表中指定位置的元素。
3.E remove(int index)移除列表中指定位置的元素(可选操作)。
4.E set(int index, E element)用指定元素替换列表中指定位置的元素(可选操作)。

1.void add(int index, E element),在列表的指定位置插入指定元素

//创建集合
List<Integer> list = new ArrayList<>();
//添加数据
list.add(1);list.add(2);list.add(3);

/*
在指定索引 "2" 位置添加数据
*/
list.add(2,2);

2.E get(int index)返回列表中指定位置的元素
get方法主要用于遍历集合

//List集合遍历的三种方式
        //1.使用普通for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //2.使用迭代器遍历
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //3.使用增强for循环
        for (int i : list){
            System.out.println(i);
        }

3.E remove(int index)移除列表中指定位置的元素

/*
移除指定元素,并返回被移除的元素
*/
Integer rNum = list.remove(2);

4.E set(int index, E element)用指定元素替换列表中指定位置的元素

/*
替换掉指定元素,返回被替换的元素
*/
Integer sNum = list.set(1, 10);

注意事项

因为List集合带有索引,所以在操作时要注意防止索引越界异常

ArrayList

介绍

位置:java.util. ArrayList<E>
特征

  • 1.实现了List接口,底层数据结构为数组查询快,增删慢
  • 2.实现不是同步的(多线程),效率高,速度快
  • 3.数组增删时,底层是通过重新创建数组,复制原数组数据实现的(所以很慢)

使用
在上方的Collection集合和List集合的示例中都使用了ArrayList集合,这里不再赘述。

【tips】

要求查询效率时应该尽量选择ArrayList集合。
ArrayList集合支持多线程,基本将Vector集合取代掉了。

LinkedList

介绍

位置:java.util.LinkedList<E>
特征

  • 1.实现了List接口,底层数据结构为链表查询慢,增删快
  • 2.实现不是同步的(多线程),效率高,速度快
  • 3.操作集合的头尾是更加方便的(有大量操作首位元素的方法

特有方法
注意:使用实现类的特有方法不能使用多态

方法信息方法作用
1.void addFirst(E e)将指定元素插入此列表的开头。
2.void addLast(E e)将指定元素添加到此列表的结尾。
3.void push(E e)将元素推入此列表所表示的堆栈。(此方法等效于 addFirst(E)。
4.E getFirst()返回此列表的第一个元素。
5.E getLast()返回此列表的最后一个元素。
6.E removeFirst()移除并返回此列表的第一个元素。
7.E removeLast()移除并返回此列表的最后一个元素。
8.E pop()从此列表所表示的堆栈处弹出一个元素。(此方法等效于 removeFirst()。

1.void addFirst(E e)将指定元素插入此列表的开头

LinkedList<String> list = new LinkedList<>();

list.addFirst("addFirst");

2.void addLast(E e)将指定元素添加到此列表的结尾

list.addLast("addLast");

3.void push(E e),将元素推入此列表所表示的堆栈。(此方法等效于 addFirst(E)

list.push("push");

4.E getFirst()返回此列表的第一个元素

String gfi = list.getFirst();

5.E getLast()返回此列表的最后一个元素

String gla = list.getLast();

6.E removeFirst()移除并返回此列表的第一个元素

String rfi = list.removeFirst();

7.E removeLast()移除并返回此列表的最后一个元素

String rla = list.removeLast();

8.E pop(),从此列表所表示的堆栈处弹出一个元素。(此方法等效于 removeFirst()

String pop = list.pop();

Vector

介绍

位置:java.util.Vector<E>
子类:Stack
特征

  • 1.从jdk 1.0开始就存在,其它集合 从jdk 1.2才出现(并且在 jdk 1.2时也实现了List接口)
  • 2.实现了List接口,底层数据结构是数组,查询快,增删慢
  • 3.实现是同步的(单线程),这是后来Vector集合逐渐被ArrayList集合取代的主要原因。

特有方法

方法信息方法作用
1.void addElement(E obj)将指定的组件添加到此向量的末尾,将其大小增加 1。
2.Enumeration<E> elements()返回此向量的组件的枚举。

【tips】

  • Enumeration接口相当于早期的迭代器。包含了两个方法,方法的功能与 jdk1.2时的迭代器类。似。

代码实例

//创建 Vector 集合
Vector<String> vector = new Vector<>();
//添加数据
vector.add("vector");
//创建 Vector的 Enumeration对象
Enumeration<String> elements = vector.elements();
//遍历 Vector 集合
while(elements.hasMoreElements()){
    String str = elements.nextElement();
    System.out.println(str);
}

Stack

了解一点就行
介绍

位置:java.util.Collection<E>
父类:Vector
特征

  • 实现了一个标准的后进先出的栈
  • 从jdk 1.0开始就存在

特有方法

API 文档的截图,简单了解,不再做详细演示
在这里插入图片描述

3.Set集合

介绍

位置:java.util.Set<E>
实现类:HashSetTreeSet
特征

  • 1.无序
  • 2.没有索引(不能使用普通的for循环的遍历)
  • 3.不允许有重复元素

HashSet

介绍

位置:java.util.Collection<E>
子类:LinkedHsahSet
特征

  • 1.存储和取出数据的元素顺序可能不一致
  • 2.底层是一个哈希表结构
    • 实质是一个HashMap实例(只用了K没用V)
    • 查询速度非常快
  • 3.实现不是同步的(多线程),效率高,速度快。
  • 4.不允许有重复的元素

HashSet使用实例

//创建HashSet集合
Set<String> set = new HashSet<>();
//向集合中添加数据
set.add("A");set.add("B");set.add("C");

//使用迭代器遍历 HashSet 集合
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}

//使用增强 for循环 遍历 HashSet 集合
for(String str : set){
    System.out.println(str);
}

HsahSet的存储规则
1.底层结构
在这里插入图片描述

2.存储过程

(1)首先计算出元素的哈希值
(2)根据哈希值对元素进行分组

3.Set集合为什么不能存储重复元素
前提:存储的元素必须重写hashCode方法和equals方法

(1)Set集合在调用add方法时add方法会调用hashCode方法判断元素哈希值是否重复,无重复直接存
(2)如果元素的哈希值重复会调用equals方法对比元素的值,不重复则存,重复则不存

注意事项

1.例如常用的 String类等,本身·已经添加了 hashCode方法和 equals方法·,可以将字符串等元素直接存进Set集合
2.如果存储到Set集合的元素是自定义类型,那么必须重写 hashCode方法和 equals方法

  • 不重写 hashCode方法和 equals方法只是保证对象的哈希值不同
  • 重写 hashCode方法和 equals方法可以保证对象中的内容不同

LinkedHsahSet

介绍

位置:java.util.LinkedHsahSet<E>
父类:HsahSet
特征

  • 1.底层是一个哈希表 + 链表(记录元素顺序)
  • 2.与 HsahSet的区别就是 LinkedHsahSet有序

【tips】

HashSet存取元素的顺序可能不一致,而LinkedHashSet可以解决这个问题。

TreeSet

介绍

位置:java.util.TreeSet<E>
子类、实现类
特征2

  • 1、不能有重复的元素;
  • 2、具有排序功能;
  • 3、TreeSet中的元素必须实现Comparable接口并重写compareTo()方法,TreeSet判断元素是否重复 、以及确定元素的顺序 靠的都是这个方法;
    • ①对于Java类库中定义的类,TreeSet可以直接对其进行存储,如String,Integer等,因为这些类已经实现了Comparable接口);
    • ②对于自定义类,如果不做适当的处理,TreeSet中只能存储一个该类型的对象实例,否则无法判断是否重复。
  • 4、依赖TreeMap。
  • 5、相对HashSet,TreeSet的优势是有序,劣势是相对读取慢。根据不同的场景选择不同的集合。

4.总结

List集合

1.有序
2.有索引
3.允许元素重复

Set集合

1.无序
2.无索引
3.不允许重复

三、Map< K,V >(双列集合)

介绍

位置:java.util.Map<K,V>
实现类:HashSetTreeSet
特征

  • 1.Map是一个双列集合,一个元素包含两个值
  • 2.key和value的数据类型可以相同也可以不同
  • 3.key值不允许重复,value值允许重复
  • 4.key和value是 一 一 对应的

【tips】
Map:键不重复,以键找值

1.HsahMap集合

HashMap集合可以看做是HashSet集合的扩展。(其实HashSet是HashMap的不完整形式
HashSet是HashMap去掉了value的结果。
那么显然HashSet加上value就变成了HashMap。

介绍

位置:java.util.HsahMap<K,V>
子类、实现类
特征

  • 1.底层是哈希表,查询快
  • 2.无序,存取元素的顺序有可能不一致(LinkedHashMap<K,V>弥补了这一缺点

常用方法

方法信息方法作用
1.V put(K key, V value)将指定的值与此映射中的指定键关联。
2.V get(Object key)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
3.V remove(Object key)如果存在一个键的映射关系,则将其从此映射中移除。
4.void clear()从此映射中移除所有映射关系。此调用返回后,该映射将为空。
5.boolean containsKey / Value(Object key)如果此映射包含指定键的映射关系,则返回 true。
6.Set keySet()返回此映射中包含的键的 Set 视图

1.V put(K key, V value),将指定的值与此映射中的指定键关联。

//创建 Map集合
Map<Integer,String> map = new HashMap<>();
/*
    向Map集合中添加键值对
    V put(K key, V value)
    返回值V:
        存储键值对时,key不存在返回 null
                    key存在返回被替换的值
*/
String strPut1 = map.put(001, "张三");

2.V get(Object key),返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。

/*
获取集合中的元素
V get(Object key)
返回值V:
        存储键值对时,key不存在返回 null
        key存在返回被替换的值
 */
String strGet1 = map.get(001);

3.V remove(Object key),如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

 /*
 	获取集合中的元素
 	V get(Object key)
 	返回值V:
    	存储键值对时,key不存在返回 null
    	key存在返回被替换的值
  */
 String strGet1 = map.get(006);

4.void clear(),从此映射中移除所有映射关系(可选操作)。此调用返回后,该映射将为空。

/*
移除集合中的所有键值对
void clear()
          从此映射中移除所有映射关系(可选操作)。此调用返回后,该映射将为空。
*/
map.clear();

5.boolean containsKey / Value(Object key),如果此映射包含指定键的映射关系,则返回 true。

/*
检测集合是否包含某个 键 / 值
boolean containsKey / Value(Object key)
返回值:
    存在true,不存在false
 */
boolean bConK1 = map.containsKey(001);
boolean bConV1 = map.containsValue("张三");

6.Set keySet(),返回此映射中包含的键的 Set 视图(用于集合的遍历

//使用keySet方法将Map集合中的key取出来
Set<Integer> set = map.keySet();

Map集合遍历的两种方式
方式一: 使用V get(Object key)方法

思路分析:
1.首先获得 K 的 Set集合
2.遍历 Set集合
3.根据 K 取出 V

//创建集合
Map<Integer,String> map = new HashMap<>();
//使用keySet方法将Map集合中的key取出来
Set<Integer> set = map.keySet();
//根据key获取对应的值(增强for循环)
for(Integer key : set){
    String value = map.get(key);
    System.out.println(key+"="+value);
}
//根据key获取对应的值(迭代器)
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
    Integer key = it.next();
    String value = map.get(key);
    System.out.println(value);
}

方式二: 使用Map的内部接口Entry

在Map集合中有个内部接口Entry(可用来遍历Map集合)
当Map集合创建后,就会在Map集合中创建一个Entry对象,用来记录键与值(键和值的映射关系)

Set<Map.Entry<K,V>> entrySet()
          返回此映射中包含的映射关系的 Set 视图。

使用Entry接口遍历集合的步骤
1.使用Map集合中的entrySet方法,把Map集合的多个Entry对象存储到Set集合
2.遍历Set集合,获取Entry元素
3.使用Entry对象的getKey和getValue方法获取键与值
//创建集合
Map<Integer,String> map = new HashMap<>();
//1.使用Map集合中的entrySet方法,把Map集合的多个Entry对象存储到Set集合
Set<Map.Entry<Integer, String>> set = map.entrySet();
//使用迭代器
Iterator<Map.Entry<Integer, String>> it = set.iterator();
while(it.hasNext()){
    Map.Entry<Integer, String> entry = it.next();
    Integer key = entry.getKey();
    String value = entry.getValue();
    System.out.println(key+"="+value);
}
//使用增强for循环
for(Map.Entry<Integer, String> entry : set){
    Integer key = entry.getKey();
    String value = entry.getValue();
    System.out.println(key+"="+value);
}

LinkedHashMap

介绍

位置:java.util.LinkedHashMap<K,V>
父类:HashMap
特征

  • 哈希表和链接列表实现,具有可预知的迭代顺序

2.TreeMap

介绍

位置:java.util.TreeMap<K,V>
特征

  • 所有的元素都是有某一固定顺序的(对Integer来说,其自然排序就是数字的升序;对String来说,其自然排序就是按照字母表排序)
  • TreeMap继承SortedMap类,保持键的有序顺序
  • 基于红黑树实现的
  • 适用于按自然顺序或自定义顺序遍历键(key)

3.Hashtable

介绍

位置:java.util.Hashtable<K,V>
特征

  • 底层是哈希表
  • 是一个线程安全的,单线程的集合
  • 键和值都不允许为空
  • Hashtable是最早期的Map jdk 1.0开始,其它的Map集合是从jdk 1.2开始

【tips】

Hashtable和Vector集合都是从jdk1.0开始,jdk1.2开始被HashMap和ArrayList取代
Hashtable的子类Properties依旧使用
Properties集合是唯一一个和IO流相结合的集合

四、Collections工具类

四个常用方法

static <T> boolean addAll(Collection<? super T> c, T... elements)
          将所有指定元素添加到指定 collection 中。
static void shuffle(List<?> list)
          使用默认随机源对指定列表进行置换。
static <T> void sort(List<T> list)
          根据指定比较器产生的顺序对指定列表进行排序。
          【注意】
          被排序的集合里边的元素必须实现Comparable接口,重写compareTo方法定义排序规则
static <T> void sort(List<T> list, Comparator<? super T> c)
          根据指定比较器产生的顺序对指定列表进行排序。
public class Demo01 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        //向集合中添加多个元素
        Collections.addAll(list,"a","b","c","d","e");
        System.out.println(list);

        //打乱集合元素顺序
        Collections.shuffle(list);
        System.out.println(list);

        //对集合元素排序
        Collections.sort(list);
        System.out.println(list);

        //根据指定比较器产生的顺序对指定列表进行排序。
        Collections.sort(list, new Comparator<String>() {
            //重写自定义的比较规则
            @Override
            public int compare(String o1, String o2) {
                return o1.charAt(0)-o2.charAt(0);
            }
        });
        System.out.println(list);

        ArrayList<Person> arrList = new ArrayList<>();
        Collections.addAll(arrList,new Person("张三",20),new Person("李四",18),new Person("啊王五",18),new Person("啵王五",18));

        Collections.sort(arrList, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //按照年龄升序排列
                int res = o1.getAge() - o2.getAge();
                //如果年龄相同则按 姓 排序
                if(res == 0){
                    res = o1.getName().charAt(0) - o2.getName().charAt(0);
                }
                return res;
            }
        });
        System.out.println(arrList);
    }

}

//自定义类
class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  1. Java集合类 — 百度百科 ↩︎

  2. Java集合类(四)—TreeSet — 简书 ↩︎

推荐阅读