【Java基础】6.java中的常用集合

【Java基础】6.java中的常用集合

学习集合的目标:

  1. 会使用集合存储数据
  2. 会遍历数据,取出其中的数据
  3. 掌握每种集合的特性

6.1 Collection集合

6.1.1 集合框架

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-auKdGD7d-1588673061936)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200221100147892.png)]

学习模式:学习顶层,使用底层

6.1.2 Collection接口常用功能

java.util 接口 Collection

它是所有单列集合最顶层的接口,里面定义了所有单列集合共性方法

任意单列集合都可以使用Collection接口中的方法

常用共性方法

add方法

向集合中添加对象,返回值是boolean值

boolean add(E e)
clear方法

移除此 collection 中的所有元素

void clear()
remove方法

从此 collection 中移除指定元素的单个实例。如果此调用移除一个元素成功,则返回 true

boolean remove(Object o)
contains方法

判断当前集合中是否包含给定对象。若包含则返回true。

boolean contains(Object o)
isEmpty方法

判断当前集合是否为空,若为空返回true,不为空返回false

boolean isEmpty()
size方法

返回当前集合中元素个数

int size()
toArray方法

返回包含此 collection 中所有元素的数组

Object[] toArray()

6.1.3 Iterator迭代器

使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口来接收(多态)

注意:Iterator接口也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型

使用格式举例

Iterator<String> it = coll.iterator();

方法

hasNext方法

如果仍有元素可以迭代,则返回 true。(换句话说,如果 next 返回了元素而不是抛出异常,则返回 true)。

boolean hasNext()
next方法

返回迭代的下一个元素

E next()

6.1.4 增强for循环

JDK 5+新特性,增强for循环。

底层也是迭代器,使用了for循环格式,简化了迭代器书写

Collection extends Iterable 所有单列集合都可以使用增强for

增强for循环:用来遍历集合和数组

使用格式:
for(集合/数组数据类型  变量名:  集合名/数组名){

	sout(变量名);

}

【注意】新的for循环必须有被遍历的目标。目标只能是Collection集合或者数组。

举例:

//增强for循环遍历
System.out.println("增强for循环遍历:");
for(Integer i:coll){
    System.out.println(i);
}

6.2 泛型

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。

泛型可以是看成一个变量,用来接收数据类型

E e : Elements 元素

T t : Type 类型

6.2.1 使用泛型的优缺点

创建集合对象时,使用泛型

好处:

  1. 避免了类型转换的麻烦,存储的是什么类型,取出就是什么类型
  2. 把运行期异常(代码运行后抛出的异常),提升到了编译期

弊端:

​ 泛型是什么类型,只能存储什么类型的数据

【集合若不使用泛型,默认类型是Object类型,容易发生异常】

6.2.2 泛型的定义与使用

泛型是一个未知的数据类型,当不确定数据类型时,可以使用泛型。

泛型可以接收任意数据类型

【创建对象】时确定泛型的数据类型

举例:定义一个含有泛型的类,并尝试使用

6.2.3 含有泛型的方法

格式:

修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){

​ 方法体;

}

【调用】时确定泛型的具体数据类型

6.2.4 含有泛型的接口

使用方式:

1.定义接口的实现类,实现接口,指定接口的泛型【先指定,后使用】

2.接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。相当于定义了一个含有泛型的类,创建对象时自动使用类的泛型数据类型。【直接使用,使用第一次时指定,不可更改】

6.2.5 泛型通配符

泛型的通配符:? 代表任意数据类型

使用方式:

  1. 不能创建对象使用
  2. 只能作为方法的参数使用
泛型的限定

上限限定:

? extends E     //代表使用的泛型只能是E类型的子类

下限限定:

? super E     //代表使用的泛型只能是E类型的父类

6.3 单列集合综合案例

6.3.1 案例介绍

按照斗地主的规则,完成洗牌发牌的动作。

具体规则:

使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张,最后三张留作底牌。

6.3.2 案例分析

  • 准备牌

54张牌存储到一个集合中

其中,有2张特殊牌:大王、小王

其他52张牌:定义一个数组/集合,存储4种花色:♠♥♣♦

​ 定义一个数组/集合,存储13个序号:2,A,K,…3

循环嵌套遍历两个数组/集合,组装52张牌

4*13=52

  • 洗牌

使用集合工具类Collections的方法

shuffle(List<?> list) 使用指定随机源对指定列表进行置换

会随机打乱集合元素顺序

  • 发牌

要求:1人17张牌,剩余3张作为底牌。

一人一张轮流发牌:使用索引对3取模

定义4个集合,存储3个玩家的牌和底牌

索引%2,有两个值(0,1)

索引%3,有三个值(0,1,2)

索引>=51,给底牌发牌

  • 看牌

直接打印集合,遍历存储玩家和底牌的集合

6.3.3 代码实现

package cn.itcast.day10.demo03Poker;

import java.util.*;

public class demo01PokerMain {
    public static void main(String[] args) {
        //1 准备牌
        Collection<String> arrayListSpecial = new ArrayList<>();
        arrayListSpecial.add("BigJoker");
        arrayListSpecial.add("SmallJoker");
        Collection<String> arrayListColor = new ArrayList<>();
        arrayListColor.add("♠");
        arrayListColor.add("♥");
        arrayListColor.add("♣");
        arrayListColor.add("♦");
        Collection<String> arrayListNum = new ArrayList<String>();
        arrayListNum.add("2");
        arrayListNum.add("A");
        arrayListNum.add("K");
        arrayListNum.add("Q");
        arrayListNum.add("J");
        arrayListNum.add("10");
        arrayListNum.add("9");
        arrayListNum.add("8");
        arrayListNum.add("7");
        arrayListNum.add("6");
        arrayListNum.add("5");
        arrayListNum.add("4");
        arrayListNum.add("3");
        //循环遍历,组装牌组
        Collection<String> Poker_heap = new ArrayList<String>();
        for(String i : arrayListColor){
            for (String j : arrayListNum)
            {
                Poker_heap.add(i+j);
            }
        }
        //最后添加大小王,完成牌组组装
        for(String i:arrayListSpecial){
            Poker_heap.add(i);
        }
        //查看牌组情况
        System.out.println("洗牌前:");
        for(String k:Poker_heap){
            System.out.print(k+" ");
        }

        //2 洗牌
        //先把牌组打乱
        Collections.shuffle((List<?>) Poker_heap);
        //查看洗牌后牌组情况
        System.out.println("");
        System.out.println("洗牌后:");
        for(String k:Poker_heap){
            System.out.print(k+" ");
        }

        //3 发牌
        //首先建桌,3个玩家
        Collection<String> Player1 = new ArrayList<>();
        Collection<String> Player2 = new ArrayList<>();
        Collection<String> Player3 = new ArrayList<>();
        //3张底牌
        Collection<String> bottom  = new ArrayList<>();
        //用迭代器来遍历牌组
        Iterator<String> it = Poker_heap.iterator();
        for (int i = 0; i < Poker_heap.size(); i++) {
            if (i>=51){
                bottom.add(it.next());
            }else if(i%3==0){
                Player1.add(it.next());
            }else if(i%3==1){
                Player2.add(it.next());
            }else if(i%3==2){
                Player3.add(it.next());
            }
        }
        //看牌
        System.out.println("");
        System.out.print("玩家1:");
        Iterator<String> it1 = Player1.iterator();
        for (int i = 0; i < Player1.size(); i++) {
            System.out.print(it1.next()+" ");
        }
        System.out.println("");
        System.out.print("玩家2:");
        Iterator<String> it2 = Player2.iterator();
        for (int i = 0; i < Player2.size(); i++) {
            System.out.print(it2.next()+" ");
        }
        System.out.println("");
        System.out.print("玩家3:");
        Iterator<String> it3 = Player3.iterator();
        for (int i = 0; i < Player3.size(); i++) {
            System.out.print(it3.next()+" ");
        }
        System.out.println("");
        System.out.print("底牌:");
        Iterator<String> it4 = bottom.iterator();
        for (int i = 0; i < bottom.size(); i++) {
            System.out.print(it4.next()+" ");
        }

    }

}

6.4 List接口

6.4.1 介绍

1.有序的集合,有索引

2.可存储重复元素

3.重写了toString方法,打印时不需要循环遍历,直接打印。

6.4.2 常用方法

add方法
boolean add(E e)

向列表的尾部添加指定的元素(可选操作)。

void add(int index,E element)

在列表的指定位置插入指定元素(可选操作)。将当前处于该位置的元素(如果有的话)和所有后续元素向右移动(在其索引中加 1)。

get方法
E get(int index)

返回列表中指定位置的元素。

set方法
E set(int index,E element)

用指定元素替换列表中指定位置的元素(可选操作)。

remove方法
E remove(int index)

移除列表中指定位置的元素(可选操作)。将所有的后续元素向左移动(将其索引减 1)。返回从列表中移除的元素。

6.4.3 List的子类

ArrayList 集合

List接口的数组实现。

java.util.ArrayList 集合数据存储的结构是数组结构。

增删慢,查找快。日常开发中,使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用集合。

LinkedList 集合

List 接口的链表实现。

实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 getremoveinsert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列双端队列

特点:

  1. 底层是链表结构:查询慢,增删快
  2. 里面包含了大量操作首尾元素的方法

注意:使用LinkedList集合特有方法,不能使用多态

addFirst方法
public void addFirst(E e)

将指定元素插入此列表的开头。

addLast方法
public void addLast(E e)

将指定元素插入此列表的结尾。

push方法
public void push(E e)

将元素推入此列表所表示的堆栈。换句话说,将该元素插入此列表的开头。此方法等效于 addFirst(E)。

getFirst方法
public E getFirst()

返回此列表的第一个元素。

getLast方法
public E getLast()

返回此列表的最后一个元素。

remove方法
public E remove()
public E removeFirst()
public E pop()

移除并返回此列表的第一个元素。

removeLast方法
public E removeLast()

移除并返回此列表的最后一个元素。

6.4.4 Vector集合

Vector 类可以实现可增长的对象数组。

与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。

特有方法

elements方法
public Enumeration<E> elements()

返回此向量的组件的枚举。返回的 Enumeration 对象将生成此向量中的所有项。生成的第一项为索引 0 处的项,然后是索引 1 处的项,依此类推。

6.5 Set 接口

6.5.1 介绍

java.util.Set接口,继承了Collection接口

Set接口特点:

  1. 不允许存储重复元素
  2. 没有索引,没有带索引的方法,也不能使用普通for循环遍历

6.5.2 HushSet类

java.util.HashSet集合 实现Set接口

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

特点:

  1. 不允许存储重复元素
  2. 没有索引,没有带索引的方法,也不能使用普通for循环遍历
  3. 是一个无序集合,存储元素和和取出元素顺序可能不一致
  4. 底层是哈希表结构(查询速度非常快)
哈希值

哈希值:是一个十进制的证书,由系统随机给出(就是对象的地址值,是逻辑地址,是模拟出来得到地址,不是实际存储地址)

在Object类中有个方法可以获取对象哈希值 int hashCode() 返回对象哈希值

哈希表的数据结构

在java 8版本之后,哈希表 = 数组 + 链表 ; 数组+ 红黑树(提高查询速度)

哈希表的特点:查询速度快

不允许重复原理
存储自定义类型元素

举例说明

存储元素{String,Integer,…,Student,Person}

必须重写hashCode方法和equals方法

要求:同名同年龄的人,视为同一个人,只能存储一次

【注意】必须重写equals方法和hashcode方法。否则equals比较的是地址,不是内容。

6.5.3 LinkedHashSet集合

java.util.LinkedHashSet集合,继承了HashSet集合

集合特点:

底层是一个哈希表+链表,多了一条链表用于记录存储顺序,保证元素有序

6.5.4 可变参数

定义一个方法需要多个参数,且多个参数类型一致,我们

【注意】参数类型确定,个数不定

可以简化为

修饰符 返回值类型 方法名称(数据类型...变量名){}

可变参数原理

底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数。

传递的参数个数可以是0个(不传递)、1、2…多个

【需求举例】

定义一个计算0-n个整数求和的方法

数据类型确定:int

数量不定:n

public static int add(int...arr){

	//System.out.println(arr);//数组地址值

	//System.out.println(arr.length);//数组长度,即整数个数

	int sum = 0;

	for(int i : arr){

		//累加求和

		sum += i;

	}

	return 0;

}

【注意事项】

1.一个方法的参数列表,只能有一个可变参数

2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾

6.6 Map集合

6.6.1 概述

java.util 接口 Map<K,V>

  • 类型参数:

    K - 此映射所维护的键的类型

    V - 映射值的类型

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

6.6.2 常用实现类

HashMap<K,V>类

特点:

  1. HashMap集合底层是哈希表,查询速度特别快
  2. HashMap集合是无序集合,存储元素和取出元素顺序可能不一致【LinkedHashMap可解决】
HashMap存储自定义类型键值
HashMap<Person,String> map = new HashMap<>();
//添加元素
map.put(new Person("李文欣",21),"学士");
map.put(new Person("唐茂淳",22),"学士");
map.put(new Person("李晗天",27),"硕士");
map.put(new Person("伍星",25),"博士");
map.put(new Person("伍星",26),"初中");
map.put(new Person("伍星",25),"小学");

//遍历方法1
for(Person key :map.keySet()){
    System.out.println(key+"="+map.get(key));
}
System.out.println("============");
//遍历方法2
Set<Map.Entry<Person, String>> entries = map.entrySet();
for (Map.Entry<Person,String> entry: entries){
    System.out.println(entry.getKey()+"="+entry.getValue());
}
LinkedHashMap<K,V>类

特点:

  1. LinkedHashMap集合底层是哈希表,保证迭代顺序
  2. LinkedHashMap集合是一个有序的集合,存储元素和取出元素顺序一致

6.6.3 常用方法

put方法
V put(K key,V value)

将指定的值与此映射中的指定键关联(可选操作)。如果此映射以前包含一个该键的映射关系,则用指定值替换旧值

get方法
V get(Object key)

返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。

remove方法
V remove(Object key)

如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。更确切地讲,如果此映射包含从满足 (keynull ? knull :key.equals(k)) 的键 k 到值 v 的映射关系,则移除该映射关系。(该映射最多只能包含一个这样的映射关系。)

containsValue方法
boolean containsValue(Object value)

如果此映射将一个或多个键映射到指定值,则返回 true。更确切地讲,当且仅当此映射至少包含一个对满足 (valuenull ? vnull : value.equals(v)) 的值 v 的映射关系时,返回 true。对于大多数 Map 接口的实现而言,此操作需要的时间可能与映射大小呈线性关系。

containsKey方法
boolean containsKey(Object key)

如果此映射包含指定键的映射关系,则返回 true。更确切地讲,当且仅当此映射包含针对满足 (keynull ? knull : key.equals(k)) 的键 k 的映射关系时,返回 true。(最多只能有一个这样的映射关系)。

keySet方法
Set<K> keySet()

返回:此映射中包含的键的 set 返回值

【可借助此方法利用键找值方式,遍历集合】

遍历方法1

方式1:

//1.用keySet方法获取set集合
Set<String> set = map.keySet();
//2.遍历set集合,获取Map集合中每个Key
//使用迭代器遍历Set集合
Iterator<String> it = set.iterator();
while (it.hasNext()){
    String key = it.next();
    //3.通过Map集合中get方法,找到value
    Integer value = map.get(key);
    System.out.println(key+"-"+value);
}
System.out.println("============");
//用增强for来遍历
for(String key:set){
    System.out.println(key+"-"+map.get(key));
}

方式2:

//利用增强for的简化遍历方式
for(String key:map.keySet()){
    System.out.println(key+"-"+map.get(key));
}

6.6.4 Entry接口

映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类

遍历方法2:使用Entry对象遍历

实现步骤:

  1. 使用Map集合中的entrySet方法,把Map集合中多个Entry对象取出,存储到一个Set集合中
  2. 遍历Set集合,获取每一个Entry对象
  3. 使用Entry对象中的方法getKey和getValue获取键值

【同理,可用迭代器,可用增强for】

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

6.6.5 过时的集合Hashtable

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DDWcNIKb-1588673061944)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200222155211436.png)]

java.util.Hashtable<K,V> 已经过时,仅需要了解

【注意】

  1. 单线程
  2. 不能存储空值

6.6.6 练习

计算一个字符串中每个字符出现的次数

用Scanner获取用户输入的字符串

思路分析

1.获取一个字符串对象【Scanner】

2.创建一个Map集合,K代表字符,V代表次数

3.遍历字符串得到每个字符【toCharArray】

4.判断Map中是否存在该K

5.若有,说明已经出现过,对应v++;若没有,说明第一次出现,使v=1

6.7 JDK 9新特性

List接口,Set接口,Map接口:

里面增加了一个静态方法of,可以给集合一次性添加多个元素

static<E> List<E> of (E...elements)

【注意】

  1. 当集合中存储元素个数已经确定情况下才能用
  2. of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
  3. of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
  4. Set接口和Map接口在调用of方法时,不能有重复元素,否则会抛出异常

6.8 双列集合综合案例

斗地主综合案例:有序版本

  1. 准备
  2. 洗牌
  3. 发牌
  4. 排序
  5. 看牌

在这里插入图片描述

代码实现
package cn.itcast.day11.demo03;

import java.util.*;

public class Doudizhu {
    public static void main(String[] args) {
        //1.准备牌
        List<String> colors =List.of("♠","♥","♣","♦");
        List<String> numbers =List.of("2","A","K","Q","J","10","9","8","7","6","5","4","3");
        //组牌
        //创建Map集合,作为牌堆
        HashMap<Integer,String> poker = new HashMap<>();
        //创建一个List存储索引
        ArrayList<Integer> pokerIndex = new ArrayList<>();
        //先放入大王和小王
        //定义一个牌的索引
        int index = 0;
        pokerIndex.add(index);
        poker.put(index++,"大王");
        pokerIndex.add(index);
        poker.put(index++,"小王");
        //两层循环,放入剩余52张

        for(String number:numbers){
            for(String color:colors){
                pokerIndex.add(index);
                poker.put(index++,color+" "+number);
            }
        }
        //查看组牌完成后的样子
        System.out.println(poker);

        //2.洗牌
        //针对索引列进行洗牌即可

        Collections.shuffle(pokerIndex);
        //3.发牌
        //首先建桌,3个玩家
        ArrayList<Integer> Player1 = new ArrayList<>();
        ArrayList<Integer> Player2 = new ArrayList<>();
        ArrayList<Integer> Player3 = new ArrayList<>();
        //3张底牌
        ArrayList<Integer> bottom = new ArrayList<>();

        for (int i = 0; i < pokerIndex.size(); i++) {
            if(i>=51){
                bottom.add(pokerIndex.get(i));
            }
            if(i%3==0){
                Player1.add(pokerIndex.get(i));
            }else if(i%3==1){
                Player2.add(pokerIndex.get(i));
            }else Player3.add(pokerIndex.get(i));
        }

        //4.排序
        //使用Collections中的方法sort(List)  默认升序
        Collections.sort(Player1);
        Collections.sort(Player2);
        Collections.sort(Player3);
        Collections.sort(bottom);

        //5.看牌
        System.out.print("玩家1:");
        for (int i = 0; i < Player1.size(); i++) {
            System.out.print(poker.get(Player1.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("玩家2:");
        for (int i = 0; i < Player2.size(); i++) {
            System.out.print(poker.get(Player2.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("玩家3:");
        for (int i = 0; i < Player3.size(); i++) {
            System.out.print(poker.get(Player3.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("底牌:");
        for (int i = 0; i < bottom.size(); i++) {
            System.out.print(poker.get(bottom.get(i))+" ");
        }
        System.out.println("");//换行
    }
}
/使用Collections中的方法sort(List)  默认升序
        Collections.sort(Player1);
        Collections.sort(Player2);
        Collections.sort(Player3);
        Collections.sort(bottom);

        //5.看牌
        System.out.print("玩家1:");
        for (int i = 0; i < Player1.size(); i++) {
            System.out.print(poker.get(Player1.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("玩家2:");
        for (int i = 0; i < Player2.size(); i++) {
            System.out.print(poker.get(Player2.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("玩家3:");
        for (int i = 0; i < Player3.size(); i++) {
            System.out.print(poker.get(Player3.get(i))+" ");
        }
        System.out.println("");//换行
        System.out.print("底牌:");
        for (int i = 0; i < bottom.size(); i++) {
            System.out.print(poker.get(bottom.get(i))+" ");
        }
        System.out.println("");//换行
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值