> 文档中心 > 【Java基础】集合 一篇文章带你看懂集合,万字详述集合

【Java基础】集合 一篇文章带你看懂集合,万字详述集合

这里写目录标题

  • 集合
    • Collection
    • **List集合概述和特点**
    • **Set集合概述和特点**
    • 4.1 泛型概述
    • Map集合

集合

Collection单列:List可重复:ArrayList、LinkedList.Set不可重复:HashSet、TreeSet
Map双列:HashMap 加粗为实现类

Collection

1.3 Collection 集合概述和使用
Collection集合概述
是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
创建Collection集合的对象
多态的方式
具体的实现类ArrayList

1.4 Collection 集合常用方法
方法名 说明
boolean add(E e) 添加元素
boolean remove(Object o) 从集合中移除指定的元素
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定的元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数

1.5 Collection 集合的遍历
Iterator(接口):迭代器,集合的专用遍历方式
Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到

Collection <String> c = new ArrayList<String>();//多态创建集合对象,需要导入ArrayList和Intertor包Interator <String> it = c.intertor();//通过集合对象获取迭代器对象c.add("hello");while(it.hasNext()){    String s = it.next();    System.out.println(s);}

迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
Iterator中的常用方法
E next():返回迭代中的下一个元素
boolean hasNext():如果迭代具有更多元素,则返回 true

List集合概述和特点

2.1 List集合概述
有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
与Set集合不同,列表通常允许重复的元素
List集合特点
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复

2.2 List集合特有方法
方法名
void add(int index,E element) 在此集合中的指定位置(已存在位置)插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int index,Eelement) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素

2.3 并发修改异常ConcurrentModificationException
产生原因
迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致(预期修改次数和实际修改次数不一致)
解决方案
用for循环遍历,然后用集合对象做对应的操作即可(Interator->for来遍历)

2.4 ListIterator:列表迭代器
通过List集合的Listlterator()方法得到,所以说它是List集合特有的迭代器(继承自Iterator)
用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

Listlterator中的常用方法
E next(): 返回迭代中的下一个元素
boolean hasNext(): 如果迭代具有更多元素,则返回 true
E previous(): 返回列表中的上一个元素
boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true
void add(E e): 将指定的元素插入列表(不会并发修改异常)

2.5增强for循环
增强for:简化数组和Collection集合的遍历
实现Iterable接口的类允许其对象成为增强型 for语句的目标
它是JDK5之后出现的,其内部原理是一个Iterator迭代器

增强for的格式:
for(元素数据类型变量名:数组或者Collection集合){
//在此处使用变量即可,
该变量就是元素
范例:

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

2.11 List集合子类特点
List集合常用子类:ArrayList,LinkedList
ArrayList:底层数据结构是数组,查询快,增删慢
LinkedList:底层数据结构是链表,查询慢,增删快

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

Set集合概述和特点

3.1 Set集合特点:不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环遍历
注意:Set是一个接口,创建对象时不能直接使用,必须使用Set的实现类(如HashSet,HashSet对集合的迭代顺序不做任何保证)

3.2 哈希值
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
public int hashCode():返回对象的哈希码值
对象的哈希值特点:
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下(hashCode方法可重写),不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
举例如下:
不同字符串哈希值可能一样,因为String中重写了hashCode方法

System.out.println("重地".hashCode());//1179395System.out.println("通话".hashCode());//1179395

3.3 HashSet集合概述和特点
底层数据结构是哈希表
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以是不包含重复元素的集合
HashSet集合练习:存储字符串并遍历

import java.util.HashSet;public class HashSetDemo {    public static void main(String[] args) { HashSet<String> hs = new HashSet<String>();  hs.add("hello");  hs.add("java");  hs.add("world"); hs.add("world");//输出结果为world java hello for (String s:hs) {//不出现重复元素且顺序错乱     System.out.println(s);      }

3.43.4 HashSet集合保证元素唯一性源码分析
HashSet集合添加一个元素的过程:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rZHaGlzu-1646752223289)(D:\C盘移动\图片\java\uTools_1646404125991.png)]
调用对象的hashCode()方法获取对象的哈希值、根据对象的哈希值计算对象的存储位置、该位置是否有元素若有则把存入的元素和以前的元素比较哈希值如果哈希值不同,会继续向下执行,把元素添加到集合
如果哈希值相同,会调用对象的equals()方法比较
如果返回false,会继续向下执行,把元素添加到集合
如果返回true,说明元素重复,不存储

3.5 常见数据结构之哈希表
JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组
JDK8以后,在长度比较长的时候,底层实现了优化

创建HashSet集合存储学生对象,要求信息相同认为同一个对象

import java.util.HashSet;public class HashSetDome2 {    public static void main(String[] args) { HashSet<Student> hs = new HashSet<>(); Student s1 = new Student("1", 1); Student s2 = new Student("2", 2); Student s3 = new Student("3", 3); Student s4 = new Student("3", 3); hs.add(s1); hs.add(s2); hs.add(s3); hs.add(s4); for (Student s : hs) {     System.out.println(s.getName() + "," + s.getAge()); }    }}//结果s3和s4都被存入并输出,这里要重写Student类中的equal和hashCode方法,如下:
 @Override    public boolean equals(Object o) { if (this == o) {     return true; } if (o == null || getClass() != o.getClass()) {     return false; } Student student = (Student) o; return age == student.age && Objects.equals(name, student.name);    }    @Override    public int hashCode() { return Objects.hash(name, age);    }

3.6 LinkedHashSet集合概述和特点
哈希表和链表实现的Set接口,具有可预测的迭代次序
由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
由哈希表保证元素唯,也就是说没有重复的元素

3.7 TreeSet集合概述和特点
元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以不包含重复元素的集合
注意:集合中存贮的元素是引用类型,基本数据类型要用其包装类

3.8 自然排序Comparable的使用
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

import java.util.TreeSet;public class TreeSetDemo {    public static void main(String[] args) {    TreeSet<Student> t = new TreeSet<Student>(); Student s1 = new Student("a",1); Student s2 = new Student("a",1); Student s3 = new Student("b",1); Student s4 = new Student("c",2); t.add(s1); t.add(s2); t.add(s3); t.add(s4); for (Student s:t ) {     System.out.println(s.getName() + "," + s.getAge()); }}}

这里要注意,在Student方法中要实现Comparable接口不然会报错;并且要重写comparableTo方法

@Overridepublic int (compareTo(Student s){//return θ;认为其他元素重复,因此只能添加一个元素//return 1 ;元素不重复,全部添加//return -1;倒序圈添加//按照年龄从小到大排序int num = this.age - s.age;//int num = s.age - this .age ;倒序//年龄相同时,按照姓名的字母顺序排序int num2 = num==0this.name.compareTo(s.name):num;return num2;

3.9比较器排序Comparator的使用
存储学生对象并遍历,创建TreeSet集合使用带参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,To2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){//这里用匿名类实现Comparator@Overridepublie int compare(Student s1, Student s2) {int num = s1.getAge(- s2.getAge();int num2 = num == 0?s1.getName().compareTo(s2.getName()) : num;return num2;}});

4.1 泛型概述

泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型
它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
泛型定义格式:
:指定一种类型的格式。这里的类型可以看成是形参
:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型泛型的好处:
把运行时期的问题提前到了编译期间
避免了强制类型转换

4.2 泛型类
泛型类的定义格式:
格式: 修饰符 class 类名 { }
范例: public class Generic{ }
此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型

public class Generic<T>private T t;    public T getT({    return t;}    public void setT(T t) {    this.t = t;}

使用如下

Generic<String> g1 = new Generic<String>();g1.setT();g1.get();

4.4 泛型接口
格式:修饰符 interface 接口名 { }
范例:public interface Generic

4.5 类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符:
List:表示元素类型未知的List,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果说我们不希望List是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以类型通配符上限:
List:它表示的类型是Number者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
类型通配符下限:
List:它表示的类型的Number或者其父类

4.7 可变参数的使用
Arrays工具类中有一个静态方法:
public static List asList(T… a):返回由指定数组支持的固定大小的列表,不能增删集合的元素,因为会改变集合的大小,可以更改set元素
List接口中有一个静态方法:
public static List of(E… elements):返回包含任意数量元素的不可变列表,返回的集合不能做增删改操作
Set接口中有一个静态方法:
public static Set of(E… elements):返回一个包含任意数量元素的不可变集合 。不能给重复元素,不能增删,无修改方法

Map集合

Map集合概述
Interface Map
K: 键的类型; V: 值的类型
将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
举例:学生的学号和姓名
创建Map集合的对象
多态的方式
具体的实现类HashMap

5.2 Map集合的基本功能
方法名 说明
V put(K key,V value) 添加元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数

5.3 Map集合的获取功能
方法名 说明
V get(Object key) 根据键获取值
Set keySet() 获取所有键的集合
Collection values() 获取所有值的集合
Set<Map.Entry> entrySet() 获取所有键值对对象的集合

5.4Map集合的遍历方式
获取所有键的集合,用keySet()方法实现
遍历键的集合,获取到每一个键。用增强for实现
根据键去找值。用get(Object key)方法实实现

Set<Map.Entry> entries =map.entrySet(); for (Map.Entry me : entries ) {     System.out.println(me.getKey() + "," + me.getValue());  }

ArrayList集合存储HashMap元素并遍历思路:
创建ArrayList集合
创建HashMap集合,并添加键值对元素
把HashMap作为元素添加到ArrayList集合
遍历ArrayList集合

import java.util.ArrayList;import java.util.HashMap;import java.util.Set;public class ArrayListIncludeHashMap {    public static void main(String[] args) { ArrayList<HashMap<String, String>> hashMaps = new ArrayList<HashMap<String, String>>(); HashMap<String, String> map1 = new HashMap<>(); map1.put("zs", "1"); map1.put("ls", "2"); map1.put("ww", "3"); HashMap<String, String> map2 = new HashMap<>(); map2.put("zs", "1"); map2.put("ls", "2"); map2.put("ww", "3"); hashMaps.add(map1); hashMaps.add(map2);//遍历时注意元素HashMap for (HashMap<String, String> a : hashMaps ) {     Set<String> keySet = a.keySet();     for (String s : keySet//同上     ) {  String v = a.get(a);  System.out.println(v + "," + s);  }}}}

需求:创建一个HashMap集合,存储三个键值对元素, 4个键值对元素的键是String,值是ArrayList,
每一个ArrayList的元素是String,并遍历
思路:
① 创建HashMap集合
② 创建ArrayList集合,并添加元素
③ 把ArrayList作为元素添加到HashMap集合
④ 遍历HashMap集合

import java.util.ArrayList;import java.util.HashMap;import java.util.Set;public class HashMapIncludeArrayList {    public static void main(String[] args) { HashMap<String, ArrayList<String>> stringArrayListHashMap = new HashMap<String, ArrayList<String>>(); ArrayList<String> arr1 = new ArrayList<String>(); ArrayList<String> arr2 = new ArrayList<>(); arr1.add("赵云"); arr1.add("诸葛亮"); stringArrayListHashMap.put("三国演义", arr1); arr2.add("孙悟空"); arr2.add("猪八戒"); stringArrayListHashMap.put("西游记", arr2); Set<String> keySet = stringArrayListHashMap.keySet();//获取所有Key的集合 for (String hashmap : keySet ) {     System.out.println(hashmap);//外出输出key     ArrayList<String> value = stringArrayListHashMap.get(hashmap);     for (String s : value     ) {  System.out.println(s);}}}}

6.1 Collections概述和使用
Collections类的概述
是针对集合操作的工具类
Collections类的常用方法
public static <T extends Comparable> void sort(List list):将指定的列表按升序排序
public static void reverse(List list):反转指定列表中元素的顺序
public static void shuffle(List list):使用默认的随机源随机排列指定的列表
终极案例,扑克游戏案例

import java.util.ArrayList;import java.util.Collections;public class PokerDemo {    public static void main(String[] args) { ArrayList<String> arr = new ArrayList<>(); String[] colors = {"♦", "❤", "♠", "♣"}; String[] numbers = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "P", "K", "A"}; for (String color : colors) {     for (String number : numbers     ) {  arr.add(color + number);     } } arr.add("大王"); arr.add("小王"); Collections.shuffle(arr); //洗牌 // System.out.println(arr); ArrayList<String> p1 = new ArrayList<>(); ArrayList<String> p2 = new ArrayList<>(); ArrayList<String> p3 = new ArrayList<>(); ArrayList<String> dp = new ArrayList<>(); //发牌 for (int i = 0; i < arr.size(); i++) {     String poker = arr.get(i);     if (i >= arr.size() - 3) {  dp.add(poker);     } else if (i % 3 == 0) {  p1.add(poker);     } else if (i % 3 == 1) {  p2.add(poker);     } else if (i % 3 == 2) {  p3.add(poker);     } }//看牌 lookPoker("1", p1); lookPoker("2", p2); lookPoker("3", p3); lookPoker("dp", dp);    }    public static void lookPoker(String name, ArrayList<String> arr) { System.out.println(name + "的牌是:"); for (String poker : arr ) {     System.out.print(poker + " "); } System.out.println();    }}

美剧天堂种子