找回密码
 立即注册
首页 业界区 安全 第 12 章 集合

第 12 章 集合

哈梨尔 5 天前
第 12 章 集合

12.1 集合的理解和好处

前面我们保存多个数据使用的是数组,那么数组有不足的地方,我们分析一下
12.1.1 数组


  • 长度开始时必须指定,而且一旦指定,不能更改
  • 保存的必须为同一类型的元素
  • 使用数组进行增加/删除元素的示意代码 – 比较麻烦
写出Person数组扩容示意代码。
  1. Person[] pers = new Person[1]; //大小是1  
  2. pers[0]=new Person();  
  3. //增加新的Person对象?  
  4. Person[] pers2 = new Person[pers.length+1]; //新创建数组  
  5. for(int i = 0; i < pers.length; i++){ //拷贝pers数组的元素到pers2  
  6.     pers2[i] = pers[i];  
  7. }  
  8. pers2[pers2.length-1] = new Person();//添加新的对象  
复制代码
12.1.2 集合


  • 可以动态保存任意多个对象,使用比较方便!
  • 提供了一系列方便的操作对象的方法:add、remove、set、get等
  • 使用集合添加,删除新元素的示意代码- 简洁了
12.2 集合的框架体系

Java 的集合类很多,主要分为两大类,如图:
<img alt="image-20250820224750255" >
<img alt="image-20250820224830028" >
  1. public class Collection_ {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         //解读
  5.         //1. 集合主要是两组(单列集合 , 双列集合)
  6.         //2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
  7.         //3. Map 接口的实现子类 是双列集合,存放的 K-V
  8.         //4. 把老师梳理的两张图记住
  9.         //Collection
  10.         //Map
  11.         ArrayList arrayList = new ArrayList();
  12.         arrayList.add("jack");
  13.         arrayList.add("tom");
  14.         HashMap hashMap = new HashMap();
  15.         hashMap.put("NO1", "北京");
  16.         hashMap.put("NO2", "上海");
  17.     }
  18. }
复制代码
12.3 Collection 接口和常用方法

12.3.1 Collection 接口实现类的特点
  1. public interface Collection<E> extends Iterable<E>  
复制代码

  • collection实现子类可以存放多个元素,每个元素可以是Object
  • 有些Collection的实现类,可以存放重复的元素,有些不可以
  • 有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
  • Collection接口没有直接的实现子类,是通过它的子接口Set 和 List 来实现的
    Collection 接口常用方法,以实现子类 ArrayList 来演示. CollectionMethod.java
  1. public class CollectionMethod {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         List list = new ArrayList();
  5. //        add:添加单个元素
  6.         list.add("jack");
  7.         list.add(10);//list.add(new Integer(10))
  8.         list.add(true);
  9.         System.out.println("list=" + list);
  10. //        remove:删除指定元素
  11.         //list.remove(0);//删除第一个元素
  12.         list.remove(true);//指定删除某个元素
  13.         System.out.println("list=" + list);
  14. //        contains:查找元素是否存在
  15.         System.out.println(list.contains("jack"));//T
  16. //        size:获取元素个数
  17.         System.out.println(list.size());//2
  18. //        isEmpty:判断是否为空
  19.         System.out.println(list.isEmpty());//F
  20. //        clear:清空
  21.         list.clear();
  22.         System.out.println("list=" + list);
  23. //        addAll:添加多个元素
  24.         ArrayList list2 = new ArrayList();
  25.         list2.add("红楼梦");
  26.         list2.add("三国演义");
  27.         list.addAll(list2);
  28.         System.out.println("list=" + list);
  29. //        containsAll:查找多个元素是否都存在
  30.         System.out.println(list.containsAll(list2));//T
  31. //        removeAll:删除多个元素
  32.         list.add("聊斋");
  33.         list.removeAll(list2);
  34.         System.out.println("list=" + list);//[聊斋]
  35. //        说明:以ArrayList实现类来演示.
  36.     }
  37. }
复制代码
12.3.2 Collection 接口遍历元素方式 1-使用 Iterator(迭代器)

基本介绍
  1. java.util  
  2. 接口 Iterator<E>  
  3. 所有已知子接口:  
  4.     ListIterator<E>, XMLStreamReader  
  5. 所有已知实现类:  
  6.     BeanContextSupport.BCSIterator, EventReaderDelegate, Scanner  
复制代码

  • Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。
  • 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
  • Iterator 的结构.[看一张图]
  • Iterator 仅用于遍历集合,Iterator 本身并不存放对象。
<img alt="image-20250820230941451" >
1.png

在调用 iterator.next() 方法之前必须要调用 iterator.hasNext() 进行检测。若不调用,且下一条记录无效,直接调用 it.next() 会抛出 NoSuchElementException 异常。   迭代器的使用案例
看案例演示 CollectionIterator.java
  1. public class CollectionIterator {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         Collection col = new ArrayList();
  5.         col.add(new Book("三国演义", "罗贯中", 10.1));
  6.         col.add(new Book("小李飞刀", "古龙", 5.1));
  7.         col.add(new Book("红楼梦", "曹雪芹", 34.6));
  8.         //System.out.println("col=" + col);
  9.         //现在希望能够遍历 col集合
  10.         //1. 先得到 col 对应的 迭代器
  11.         Iterator iterator = col.iterator();
  12.         //2. 使用while循环遍历
  13. //        while (iterator.hasNext()) {//判断是否还有数据
  14. //            //返回下一个元素,类型是Object
  15. //            Object obj = iterator.next();
  16. //            System.out.println("obj=" + obj);
  17. //        }
  18.         //一个快捷键,快速生成 while => itit
  19.         //显示所有的快捷键的的快捷键 ctrl + j
  20.         while (iterator.hasNext()) {
  21.             Object obj = iterator.next();
  22.             System.out.println("obj=" + obj);
  23.         }
  24.         //3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素
  25.         //   iterator.next();//NoSuchElementException
  26.         //4. 如果希望再次遍历,需要重置我们的迭代器
  27.         iterator = col.iterator();
  28.         System.out.println("===第二次遍历===");
  29.         while (iterator.hasNext()) {
  30.             Object obj = iterator.next();
  31.             System.out.println("obj=" + obj);
  32.         }
  33.     }
  34. }
  35. class Book {
  36.     private String name;
  37.     private String author;
  38.     private double price;
  39.     public Book(String name, String author, double price) {
  40.         this.name = name;
  41.         this.author = author;
  42.         this.price = price;
  43.     }
  44.     public String getName() {
  45.         return name;
  46.     }
  47.     public void setName(String name) {
  48.         this.name = name;
  49.     }
  50.     public String getAuthor() {
  51.         return author;
  52.     }
  53.     public void setAuthor(String author) {
  54.         this.author = author;
  55.     }
  56.     public double getPrice() {
  57.         return price;
  58.     }
  59.     public void setPrice(double price) {
  60.         this.price = price;
  61.     }
  62.     @Override
  63.     public String toString() {
  64.         return "Book{" +
  65.                 "name='" + name + '\'' +
  66.                 ", author='" + author + '\'' +
  67.                 ", price=" + price +
  68.                 '}';
  69.     }
  70. }
复制代码
12.3.3 Collection 接口遍历对象方式 2 - for 循环增强

增强 for 循环,可以代替 iterator 迭代器,特点:增强 for 就是简化版的 iterator,本质一样。只能用于遍历集合或数组。
基本语法
  1. for(元素类型 元素名 : 集合名或数组名) {  
  2.     访问元素  
  3. }  
复制代码
案例演示
CollectionFor.java
  1. for (Object object : col) {  
  2.     System.out.println(object);  
  3. }  
复制代码
  1. public class CollectionFor {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         Collection col = new ArrayList();
  5.         col.add(new Book("三国演义", "罗贯中", 10.1));
  6.         col.add(new Book("小李飞刀", "古龙", 5.1));
  7.         col.add(new Book("红楼梦", "曹雪芹", 34.6));
  8.         //解读
  9.         //1. 使用增强for, 在Collection集合
  10.         //2. 增强for, 底层仍然是迭代器
  11.         //3. 增强for可以理解成就是简化版本的 迭代器遍历
  12.         //4. 快捷键方式 I
  13. //        for (Object book : col) {
  14. //            System.out.println("book=" + book);
  15. //        }
  16.         for (Object o : col) {
  17.             System.out.println("book=" + o);
  18.         }
  19.         //增强for,也可以直接在数组使用
  20. //        int[] nums = {1, 8, 10, 90};
  21. //        for (int i : nums) {
  22. //            System.out.println("i=" + i);
  23. //        }
  24.     }
  25. }
复制代码
12.4 List 接口和常用方法

12.4.1 List 接口基本介绍

List 接口是 Collection 接口的子接口 List.java

  • List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
  • List 集合中的每个元素都有其对应的顺序索引,即支持索引。 [案例]
  • List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
  • JDK API 中 List 接口的实现类有:
    1. List list = new ArrayList();  
    2. list.add("tom");  
    3. list.add("jack");  
    4. list.add("mary");  
    5. list.add("smith");  
    6. list.add("smith2");  
    7. list.add("kristina");  
    8. System.out.println(list);  
    9. // 3的案例  
    10. System.out.println(list.get(4));//smith2  
    复制代码
    常用的有:ArrayList、LinkedList 和 Vector。
  1. public class List_ {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         //1. List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
  5.         List list = new ArrayList();
  6.         list.add("jack");
  7.         list.add("tom");
  8.         list.add("mary");
  9.         list.add("hsp");
  10.         list.add("tom");
  11.         System.out.println("list=" + list);
  12.         //2. List集合中的每个元素都有其对应的顺序索引,即支持索引
  13.         //   索引是从0开始的
  14.         System.out.println(list.get(3));//hsp
  15.         //3.
  16.     }
  17. }
复制代码
12.4.2 List接口的常用方法
  1. public class ListMethod {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         List list = new ArrayList();
  5.         list.add("张三丰");
  6.         list.add("贾宝玉");
  7. //        void add(int index, Object ele):在index位置插入ele元素
  8.         //在index = 1的位置插入一个对象
  9.         list.add(1, "拉里");
  10.         System.out.println("list=" + list);
  11. //        boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
  12.         List list2 = new ArrayList();
  13.         list2.add("jack");
  14.         list2.add("tom");
  15.         list.addAll(1, list2);
  16.         System.out.println("list=" + list);
  17. //        Object get(int index):获取指定index位置的元素
  18.         //说过
  19. //        int indexOf(Object obj):返回obj在集合中首次出现的位置
  20.         System.out.println(list.indexOf("tom"));//2
  21. //        int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
  22.         list.add("拉里");
  23.         System.out.println("list=" + list);
  24.         System.out.println(list.lastIndexOf("拉里"));
  25. //        Object remove(int index):移除指定index位置的元素,并返回此元素
  26.         list.remove(0);
  27.         System.out.println("list=" + list);
  28. //        Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
  29.         list.set(1, "玛丽");
  30.         System.out.println("list=" + list);
  31. //        List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
  32.         // 注意返回的子集合 fromIndex <= subList < toIndex
  33.         List returnlist = list.subList(0, 2);
  34.         System.out.println("returnlist=" + returnlist);
  35.     }
  36. }
复制代码
在开发中,需要线程同步安全时,考虑使用 Vector
  1. public class ListExercise {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         /*
  5.         添加10个以上的元素(比如String "hello" ),在2号位插入一个元素"教育",
  6.         获得第5个元素,删除第6个元素,修改第7个元素,在使用迭代器遍历集合,
  7.         要求:使用List的实现类ArrayList完成。
  8.          */
  9.         List list = new ArrayList();
  10.         for (int i = 0; i < 12; i++) {
  11.             list.add("hello" + i);
  12.         }
  13.         System.out.println("list=" + list);
  14.         //在2号位插入一个元素"教育"
  15.         list.add(1, "教育");
  16.         System.out.println("list=" + list);
  17.         //获得第5个元素
  18.         System.out.println("第五个元素=" + list.get(4));
  19.         //删除第6个元素
  20.         list.remove(5);
  21.         System.out.println("list=" + list);
  22.         //修改第7个元素
  23.         list.set(6, "三国演义");
  24.         System.out.println("list=" + list);
  25.         //在使用迭代器遍历集合
  26.         Iterator iterator = list.iterator();
  27.         while (iterator.hasNext()) {
  28.             Object obj =  iterator.next();
  29.             System.out.println("obj=" + obj);
  30.         }
  31.     }
  32. }
复制代码
</ol>12.6.2 Vector 和 ArrayList 的比较

底层结构版本线程安全(同步)效率扩容倍数ArrayList可变数组jdk1.2不安全,效率高如果有参构造1.5倍
如果是无参
1.第一次10
2.从第二次开始1.5扩Vector可变数组 Object[]jdk1.0安全,效率不高如果是无参,默认10
,满后,就按2倍扩容
如果指定大小,则每次直接按2倍扩容。12.7 LinkedList 底层结构

12.7.1 LinkedList 的全面说明


  • LinkedList 底层实现了双向链表双端队列特点
  • 可以添加任意元素(元素可以重复),包括 null
  • 线程不安全,没有实现同步
12.7.2 LinkedList 的底层操作机制

2.png
  1. public class ListFor {
  2.     @SuppressWarnings({"all"})
  3.     public static void main(String[] args) {
  4.         //List 接口的实现子类 Vector LinkedList
  5.         //List list = new ArrayList();
  6.         //List list = new Vector();
  7.         List list = new LinkedList();
  8.         list.add("jack");
  9.         list.add("tom");
  10.         list.add("鱼香肉丝");
  11.         list.add("北京烤鸭子");
  12.         //遍历
  13.         //1. 迭代器
  14.         Iterator iterator = list.iterator();
  15.         while (iterator.hasNext()) {
  16.             Object obj =  iterator.next();
  17.             System.out.println(obj);
  18.         }
  19.         System.out.println("=====增强for=====");
  20.         //2. 增强for
  21.         for (Object o : list) {
  22.             System.out.println("o=" + o);
  23.         }
  24.         System.out.println("=====普通for====");
  25.         //3. 使用普通for
  26.         for (int i = 0; i < list.size(); i++) {
  27.             System.out.println("对象=" + list.get(i));
  28.         }
  29.     }
  30. }
复制代码
12.7.3 LinkedList的增删改查案例
  1. transient Object[] elementData; // transient 表示瞬间,短暂的,表示该属性不会被序列号  
复制代码
12.8 ArrayList 和 LinkedList 比较

12.8.1 ArrayList 和 LinkedList 的比较

底层结构增删的效率改查的效率ArrayList可变数组较低
数组扩容较高LinkedList双向链表较高,通过链表追加较低如何选择 ArrayList 和 LinkedList:

  • 如果改查操作多,选择 ArrayList
  • 如果增删操作多,选择 LinkedList
  • 一般程序中 80%-90% 是查询,因此大部分情况选 ArrayList
  • 项目中灵活根据业务选,可能一个模块用 ArrayList,另一个用 LinkedList
12.9 Set 接口和常用方法

12.9.1 Set 接口基本介绍


  • 无序(添加和取出顺序不一致),没有索引 [后面演示]
  • 不允许重复元素,最多包含一个 null
  • JDK API 中 Set 接口的实现类有:
    1. public class Vector<E>  
    2.     extends AbstractList<E>  
    3.     implements List<E>, RandomAccess, Cloneable, Serializable  
    复制代码
12.9.2 Set 接口的常用方法

和 List 接口一样,Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样
12.9.3 Set 接口的遍历方式

同 Collection 的遍历方式一样,因为 Set 接口是 Collection 接口的子接口。

  • 可以使用迭代器
  • 增强 for
  • 不能使用索引的方式来获取
12.9.4 Set 接口的常用方法举例
  1. protected Object[] elementData;  
复制代码
12.10.3 HashSet 底层机制说明

分析HashSet底层是HashMap, HashMap底层是(数组+链表+红黑树)
3.png

4.png
  1. public synchronized E get(int index) {  
  2.     if (index >= elementCount)  
  3.         throw new ArrayIndexOutOfBoundsException(index);  
  4.     return elementData(index);  
  5. }  
复制代码
5.png

[code]public class HashSetIncrement {    public static void main(String[] args) {        /*        HashSet底层是HashMap, 第一次添加时,table 数组扩容到 16,        临界值(threshold)是 16*加载因子(loadFactor)是0.75 = 12        如果table 数组使用到了临界值 12,就会扩容到 16 * 2 = 32,        新的临界值就是 32*0.75 = 24, 依次类推         */        HashSet hashSet = new HashSet();//        for(int i = 1; i = MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),        否则仍然采用数组扩容机制         *///        for(int i = 1; i  Node -> 加入table , 就算是增加了一个size++         */        for(int i = 1; i
您需要登录后才可以回帖 登录 | 立即注册