JavaSE基础复习五:集合

本文最后更新于:2021年7月23日 晚上


JavaSE基础复习五:集合

常见数据结构

  • 栈:FILO

  • 队列:FIFO

  • 数组:查询快,增删慢

  • 链表:增删快,查询慢(对比数组)

  • 哈希表:数据唯一,通过元素计算存储位置

    • JDK8之前,底层采用数组+链表实现,可以当成一个元素为链表的数组

    • JDK8之后,在长度较长的时候,地层实现了优化

集合体系

集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变

  • Collection(接口):单列集合

    • List(接口):元素可重复

      • ArrayList(实现类)

      • LinkedList(实现类)

    • Set(接口):元素不可重复

      • HashSet(实现类)

      • TreeSet(实现类)

  • Map(接口):双列集合

    • HashMap(实现类)

Collection的常用方法

方法名 说明
boolean add(E e) 添加元素
boolean remove(Object o) 从集合中移除指定元素,多个相同元素的时候,删除第一个
void clear() 清空集合所有元素
boolean contains(Object o) 判断集合中是否存在指定的元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数

Collection集合遍历

iterator:迭代器,集合的专用遍历方式

  • Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到

  • 迭代器是通过iterator()方法得到的,所以我们说它是依赖于集合而存在的

Iterator中的常用方法

  • E next():返回迭代中的下一个元素

  • boolean hasNext():如果还有元素可以遍历,则返回true

使用:

1
2
3
4
5
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String e = it.next();
System.out.println(e);
}

List集合

List集合概述:

  • 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素

  • 与Set集合不同,列表通常允许重复的元素

List集合特点:

  • 有序:存储和去除的元素顺序一致

  • 可重复:存储元素可重复

List集合特有方法

方法名 说明
void $add$(int index, E element) 在指定处插入指定元素
E $remove$(int index) 删除指定索引处的元素,返回被删除的元素
E $set$(int index, E element) 修改指定索引处的元素,返回被修改的元素
E $get$(int index) 返回指定索引处的元素

注意问题:

  • 使用通过iterator()方法获取的迭代器迭代时,集合对象使用add方法会修改集合中元素的个数,会造成地带器获取元素中判断预期修改值和实际修改值不一致而抛出并发修改异常,因此,用迭代器是不要去修改数据

  • 但是可以用for循环替代,进行值的修改

    1
    2
    3
    4
    5
    6
    7
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
    String s = iterator.next();
    if (s.equals("hello")) {
    list.add("wuwuwu"); // 报错
    }
    }

ListIterator

  • 特点:用于允许程序员沿任意方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代的当前位置

  • 获取迭代器:通过List集合的listIterator()方法获取,是List集合特有的迭代器

    方法 说明
    E next() 返回迭代中的下一个元素
    boolean hasNext() 如果迭代器具有更多元素,则返回true
    E previous() 返回列表中的上一个元素
    boolean hasPrevious() 如果此列表迭代器在反方向上具有更多元素,则返回true
    void add(E e) 将指定的元素插入列表,不会产生并发修改异常
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ListIterator<String> iterator = list.listIterator();
    while (iterator.hasNext()) {
    System.out.println(iterator.next());
    }

    System.out.println("===================");

    while (iterator.hasPrevious()) {
    System.out.println(iterator.previous());
    }

    System.out.println("===================");

    while (iterator.hasNext()) {
    if (iterator.next().equals("hello")) {
    iterator.add("hahaha"); // 不报错,在hello后面添加元素
    }
    }
    System.out.println(list);

增强for循环(foreach)

  • 作用:简化数组和Collection集合的遍历

    • 实现Iterable接口的类允许其对象称为增强型for语句的目标

    • JDK5之后出现,内部原理是一个Iterator迭代器

  • 格式

    1
    2
    3
    4
    5
    6
    7
    8
    for (元素数据类型 变量名:数组或者Collection集合) {
    // 在此处使用变量,该变量就是元素
    }

    int[] arr={1,2,3,4,5};
    for(int i:arr){
    System.out.print(i);
    }

List的常见实现

ArrayList
  • 数组实现,查询快,增删慢。具体见JavaSE基础复习一的集合基础ArrayList
LinkedList
  • 双链表实现,查询慢,增删快

  • 特有方法

    方法名 说明
    public void addFirst(E e) 在该列表开头插入指定的元素
    public void addLast(E e) 将指定的元素追加到此列表的末尾
    public E getFirst() 返回列表的第一个元素
    public E gerLast() 返回列表的最后一个元素
    public E removeFirst() 从此列表中删除并返回第一个元素
    public E removeLast() 从此列表中删除并返回最后一个元素

Set集合

不包含重复元素,迭代顺序不作任何保证

Set集合常用函数

  • remove()

  • add()

  • size()

  • contains()

  • toArray()

  • copyOf(Collection<? extends E> coll):静态方法,返回一个带给定元素但不可修改的集合

  • copyOf(Set set):拷贝某个集合,返回不可修改的新集合

Hash值

  • JDK根据对象的地址或者字符串或者数字计算出来的int类型的数值

  • Object类中有一个方法可以获取对象的哈希值:HashCode()

  • 特点

    • 同一个对象计算对此Hash值,一定是相同的

    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现通过对象内的数据来计算哈希值,让不同对象的哈希值相同。

常用实现类

HashSet
  • 底层数据结构由哈希表实现

  • 对集合的迭代顺序不做任何保证,也就是说不保证存储和取出元素的顺序一致

  • 没有带索引的访问方法,所以不能使用普通for循环遍历,可以用迭代器和foreach进行遍历

  • 不包含重复元素:HashSet的add()方法流程如下,要保证元素的唯一性,需要重写hashCode()和equals()方法

LinkedHashSet

继承自HashSet

  • 具有可预测的迭代顺序:哈希表和链表实现的Set接口
  • 元素的存储和取出顺序是一致的:有链表保证元素有序
  • 元素依然唯一:由哈希表保证元素的唯一性
TreeSet
  • 元素有序,不是存入和取出的顺序,而是按照一定规则进行排序,取决于使用什么构造函数

    • TreeSet():创建一个空的,根据其元素的自然顺序进行排序的集合

    • TreeSet(Comparator comparator):创建一个空的,根据指定的比较器进行排序的集合

      注意

    • 如果集合创建时指定了比较器,则优先使用传入的比较器(无论传入的对象类是否实现Comparator接口)

    • 如果没有指定比较器,集合的元素的类需要实现Comparator接口:

      • 重写compareTo(E e)方法

      • **返回负数表示降序排列,返回正数表示升序排列,返回0表示元素相等(是同一个元素),则该元素在加入时会失败 **。

        例如:String类实现了Comparator接口,可以直接作为集合元素加入创建的集合,否则add元素会因为没有实现该接口而报错

    • 如果对象类有多个数据字段,则需要考虑所有的字段,避免其实是不同的对象但却无法加入集合的问题

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      // 存入的对象类实现Comparator接口,重写compare方法
      class TSTest implements Comparable<TSTest> {
      private String data;

      public TSTest(String data) {
      this.data = data;
      }

      @Override
      public int compareTo(TSTest o) {
      return data.compareTo(o.getData());
      }
      }


      // 创建TreeSet集合,传入实现Comparator的匿名内部类
      TreeSet<TSTest> ts = new TreeSet<>(new Comparator<TSTest>() {
      @Override
      public int compare(TSTest o1, TSTest o2) {
      return 1;
      }
      });
  • 不包含重复元素

  • 没有带索引的方法,不能使用普通for进行遍历

Map集合

Map集合概述

  • Interface Map<K, V>,K:键的类型;V:值的类型
  • 将键映射到值的对象,不能包含重复的键,每个键可以映射到最多一个值,put方法添加元素,key相同,后面的值覆盖前面的值
  • 由于底层是哈希表实现,要保证Key的唯一性,传入的Key对象需要重写hashCode()和equals()方法,String,基础类型的包装类本身就实现了

常用实现类

HashMap

常用方法

方法名 说明
V put(K key, V value) 添加元素
V remove(Object Key) 根据键删除键值对
void clear() 移除所有键值对
boolean containsKey(Object Key) 判断集合是否包含指定的键
boolean containsValue(Object Value) 判断集合是否包含指定的值
Boolean isEmpty() 判断集合是否为空
int size() 集合的长度(键值对个数)
V object(Object Key) 根据键获取值
Set keySet() 获取所有键的集合
Collection vlaues() 获取所有值的集合
Set<Map.Entry<K,V>> entrySet() 键值对对象集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Map<String, String> map = new HashMap<>();
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
System.out.println("---------");
System.out.println(map);
map.remove("张无忌");
System.out.println(map);
System.out.println("---------");
System.out.println(map.containsKey("杨过"));
System.out.println(map.containsKey("啦啦啦"));
System.out.println(map.containsValue("黄蓉"));
System.out.println(map.containsValue("啦啦啦"));
System.out.println("---------");
System.out.println(map.isEmpty());
map.clear();
System.out.println(map);
System.out.println(map.isEmpty());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Map<String, String> map = new HashMap<>();
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
System.out.println(map.get("杨过"));
System.out.println("--------");
Set<String> keySet = map.keySet();
for (String s : keySet) {
System.out.println(s);
}
System.out.println("--------");
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}

Map集合的遍历

  1. 通过keySet()方法获取keySet,再通过遍历keySet,通过get(Object Key)方法获得对应的值
  2. 通过entrySet()方法获取键值对的集合entrySet(里面存储的没有个对象都是Map.Entry<K,V>对象),然后遍历entrySet集合,然后每一个对象通过getKey()和getValue()方法获取键和值
1
2
3
4
5
6
7
8
9
10
11
12
13
// 1
Set<String> keySet = map.keySet();
for (String s : keySet) {
System.out.println("<"+s+","+map.get(s)+">");
}
System.out.println("------------");

// 2
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println("<"+entry.getKey()+","+entry.getValue()+">");
}
System.out.println("------------");

Collections

Collections类概述:针对集合操作的工具类

常用方法

方法名 说明
public static <T extends Comparator<? super T>> void sort(List list) 将指定的列表按升序排列
public static void reverse(List<?> list) 反转指定列表中元素的顺序
public static void shuffle(List<?> list) 使用默认的随机源随机排列指定的列表
1
2
3
4
5
6
7
8
9
10
11
12
ArrayList<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
list.add(4);
System.out.println(list.toString());

Collections.sort(list);
System.out.println(list.toString());

Collections.shuffle(list);
System.out.println(list.toString());

小例子:发牌

存牌,洗牌,发牌,展示牌组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package javaBasis.collectionLearn;

import java.util.*;

public class Poker {
private HashMap<Integer,String> cards = new HashMap<>(); // 牌,以及对应的序号
private ArrayList<Integer> order = new ArrayList<>(); // 当前的牌顺序

private TreeSet<Integer> first = new TreeSet<>(); // 第一个人的牌
private TreeSet<Integer> second = new TreeSet<>(); // 第二个人的牌
private TreeSet<Integer> third = new TreeSet<>(); // 第三个人的牌
private TreeSet<Integer> dp = new TreeSet<>(); // 底牌

public static void main(String[] args) {
new Poker().play();
}

public Poker() {
String[] num = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
String[] type = {"♥", "♠", "♦", "♣"};
int count = 0;
for (int i = 0; i < num.length; i++) {
for (int j = 0; j < type.length; j++) {
cards.put(count, type[j]+num[i]);
order.add(count++);
}
}
cards.put(count, "小王");
order.add(count++);
cards.put(count, "大王");
order.add(count);

System.out.print("所有的牌:");
Set<Integer> keySet = cards.keySet();
for (Integer key : keySet) {
System.out.print(cards.get(key)+" ");
}
System.out.println();
}

public void play() {
this.shuffle();
this.licensing();
this.showCards("第一个人", first);
this.showCards("第二个人", second);
this.showCards("第三个人", third);
this.showCards("底牌", dp);
}

// 洗牌
private void shuffle() {
Collections.shuffle(order);
}

// 发牌
private void licensing() {
this.first.clear();
this.second.clear();
this.third.clear();
for (int i = 0; i < order.size(); i++) {
int key = order.get(i);
if (i >= order.size() - 3) {
this.dp.add(key);
} else if (i % 3==0 ) {
this.first.add(key);
} else if (i % 3 == 1) {
this.second.add(key);
} else {
this.third.add(key);
}
}
}

// 显示牌
private void showCards(String name, TreeSet<Integer> ts) {
System.out.print(name+"的牌是:");
for (Integer key : ts) {
Set<Integer> keySet = cards.keySet();
System.out.print(cards.get(key) + " ");
}
System.out.println();
}
}

1
2
3
4
5
所有的牌:♥3 ♠3 ♦3 ♣3 ♥4 ♠4 ♦4 ♣4 ♥5 ♠5 ♦5 ♣5 ♥6 ♠6 ♦6 ♣6 ♥7 ♠7 ♦7 ♣7 ♥8 ♠8 ♦8 ♣8 ♥9 ♠9 ♦9 ♣9 ♥10 ♠10 ♦10 ♣10 ♥J ♠J ♦J ♣J ♥Q ♠Q ♦Q ♣Q ♥K ♠K ♦K ♣K ♥A ♠A ♦A ♣A ♥2 ♠2 ♦2 ♣2 小王 大王 
第一个人的牌是:♥3 ♦3 ♣3 ♥4 ♠4 ♣4 ♣5 ♥7 ♥9 ♦9 ♥10 ♣10 ♥J ♥K ♣K ♥A 小王
第二个人的牌是:♦4 ♠5 ♦5 ♠6 ♦6 ♠7 ♠8 ♣8 ♦10 ♠J ♦J ♠Q ♣Q ♠A ♦A ♠2 大王
第三个人的牌是:♥5 ♥6 ♣6 ♦7 ♣7 ♥8 ♦8 ♠9 ♣9 ♠10 ♥Q ♦Q ♠K ♦K ♣A ♥2 ♣2
底牌的牌是:♠3 ♣J ♦2