哈梨尔 发表于 5 天前

第 12 章 集合

第 12 章 集合

12.1 集合的理解和好处

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


[*]长度开始时必须指定,而且一旦指定,不能更改
[*]保存的必须为同一类型的元素
[*]使用数组进行增加/删除元素的示意代码 – 比较麻烦
写出Person数组扩容示意代码。
Person[] pers = new Person; //大小是1
pers=new Person();

//增加新的Person对象?
Person[] pers2 = new Person; //新创建数组
for(int i = 0; i < pers.length; i++){ //拷贝pers数组的元素到pers2
    pers2 = pers;
}
pers2 = new Person();//添加新的对象12.1.2 集合


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

Java 的集合类很多,主要分为两大类,如图:
<img alt="image-20250820224750255" ><img alt="image-20250820224830028" >public class Collection_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      //解读
      //1. 集合主要是两组(单列集合 , 双列集合)
      //2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
      //3. Map 接口的实现子类 是双列集合,存放的 K-V
      //4. 把老师梳理的两张图记住
      //Collection
      //Map
      ArrayList arrayList = new ArrayList();
      arrayList.add("jack");
      arrayList.add("tom");

      HashMap hashMap = new HashMap();
      hashMap.put("NO1", "北京");
      hashMap.put("NO2", "上海");
    }
}12.3 Collection 接口和常用方法

12.3.1 Collection 接口实现类的特点

public interface Collection<E> extends Iterable<E>
[*]collection实现子类可以存放多个元素,每个元素可以是Object
[*]有些Collection的实现类,可以存放重复的元素,有些不可以
[*]有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
[*]Collection接口没有直接的实现子类,是通过它的子接口Set 和 List 来实现的
Collection 接口常用方法,以实现子类 ArrayList 来演示. CollectionMethod.java
public class CollectionMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      List list = new ArrayList();
//      add:添加单个元素
      list.add("jack");
      list.add(10);//list.add(new Integer(10))
      list.add(true);
      System.out.println("list=" + list);
//      remove:删除指定元素
      //list.remove(0);//删除第一个元素
      list.remove(true);//指定删除某个元素
      System.out.println("list=" + list);
//      contains:查找元素是否存在
      System.out.println(list.contains("jack"));//T
//      size:获取元素个数
      System.out.println(list.size());//2
//      isEmpty:判断是否为空
      System.out.println(list.isEmpty());//F
//      clear:清空
      list.clear();
      System.out.println("list=" + list);
//      addAll:添加多个元素
      ArrayList list2 = new ArrayList();
      list2.add("红楼梦");
      list2.add("三国演义");
      list.addAll(list2);
      System.out.println("list=" + list);
//      containsAll:查找多个元素是否都存在
      System.out.println(list.containsAll(list2));//T
//      removeAll:删除多个元素
      list.add("聊斋");
      list.removeAll(list2);
      System.out.println("list=" + list);//[聊斋]
//      说明:以ArrayList实现类来演示.

    }
}12.3.2 Collection 接口遍历元素方式 1-使用 Iterator(迭代器)

基本介绍
java.util
接口 Iterator<E>
所有已知子接口:
    ListIterator<E>, XMLStreamReader
所有已知实现类:
    BeanContextSupport.BCSIterator, EventReaderDelegate, Scanner
[*]Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。
[*]所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
[*]Iterator 的结构.[看一张图]
[*]Iterator 仅用于遍历集合,Iterator 本身并不存放对象。
<img alt="image-20250820230941451" >
在调用 iterator.next() 方法之前必须要调用 iterator.hasNext() 进行检测。若不调用,且下一条记录无效,直接调用 it.next() 会抛出 NoSuchElementException 异常。   迭代器的使用案例
看案例演示 CollectionIterator.java
public class CollectionIterator {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {

      Collection col = new ArrayList();

      col.add(new Book("三国演义", "罗贯中", 10.1));
      col.add(new Book("小李飞刀", "古龙", 5.1));
      col.add(new Book("红楼梦", "曹雪芹", 34.6));


      //System.out.println("col=" + col);
      //现在希望能够遍历 col集合
      //1. 先得到 col 对应的 迭代器
      Iterator iterator = col.iterator();
      //2. 使用while循环遍历
//      while (iterator.hasNext()) {//判断是否还有数据
//            //返回下一个元素,类型是Object
//            Object obj = iterator.next();
//            System.out.println("obj=" + obj);
//      }
      //一个快捷键,快速生成 while => itit
      //显示所有的快捷键的的快捷键 ctrl + j
      while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);

      }
      //3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素
      //   iterator.next();//NoSuchElementException
      //4. 如果希望再次遍历,需要重置我们的迭代器
      iterator = col.iterator();
      System.out.println("===第二次遍历===");
      while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);

      }

    }
}

class Book {
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
      this.name = name;
      this.author = author;
      this.price = price;
    }

    public String getName() {
      return name;
    }

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

    public String getAuthor() {
      return author;
    }

    public void setAuthor(String author) {
      this.author = author;
    }

    public double getPrice() {
      return price;
    }

    public void setPrice(double price) {
      this.price = price;
    }

    @Override
    public String toString() {
      return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}12.3.3 Collection 接口遍历对象方式 2 - for 循环增强

增强 for 循环,可以代替 iterator 迭代器,特点:增强 for 就是简化版的 iterator,本质一样。只能用于遍历集合或数组。
基本语法
for(元素类型 元素名 : 集合名或数组名) {
    访问元素
}案例演示
CollectionFor.java
for (Object object : col) {
    System.out.println(object);
}public class CollectionFor {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      Collection col = new ArrayList();

      col.add(new Book("三国演义", "罗贯中", 10.1));
      col.add(new Book("小李飞刀", "古龙", 5.1));
      col.add(new Book("红楼梦", "曹雪芹", 34.6));

      //解读
      //1. 使用增强for, 在Collection集合
      //2. 增强for, 底层仍然是迭代器
      //3. 增强for可以理解成就是简化版本的 迭代器遍历
      //4. 快捷键方式 I
//      for (Object book : col) {
//            System.out.println("book=" + book);
//      }
      for (Object o : col) {
            System.out.println("book=" + o);
      }

      //增强for,也可以直接在数组使用
//      int[] nums = {1, 8, 10, 90};
//      for (int i : nums) {
//            System.out.println("i=" + i);
//      }


    }
}12.4 List 接口和常用方法

12.4.1 List 接口基本介绍

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

[*]List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
[*]List 集合中的每个元素都有其对应的顺序索引,即支持索引。 [案例]
[*]List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
[*]JDK API 中 List 接口的实现类有:List list = new ArrayList();
list.add("tom");
list.add("jack");
list.add("mary");
list.add("smith");
list.add("smith2");
list.add("kristina");
System.out.println(list);
// 3的案例
System.out.println(list.get(4));//smith2常用的有:ArrayList、LinkedList 和 Vector。
public class List_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      //1. List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
      List list = new ArrayList();
      list.add("jack");
      list.add("tom");
      list.add("mary");
      list.add("hsp");
      list.add("tom");
      System.out.println("list=" + list);
      //2. List集合中的每个元素都有其对应的顺序索引,即支持索引
      //   索引是从0开始的
      System.out.println(list.get(3));//hsp
      //3.
    }
}12.4.2 List接口的常用方法

public class ListMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      List list = new ArrayList();
      list.add("张三丰");
      list.add("贾宝玉");
//      void add(int index, Object ele):在index位置插入ele元素
      //在index = 1的位置插入一个对象
      list.add(1, "拉里");
      System.out.println("list=" + list);
//      boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
      List list2 = new ArrayList();
      list2.add("jack");
      list2.add("tom");
      list.addAll(1, list2);
      System.out.println("list=" + list);
//      Object get(int index):获取指定index位置的元素
      //说过
//      int indexOf(Object obj):返回obj在集合中首次出现的位置
      System.out.println(list.indexOf("tom"));//2
//      int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
      list.add("拉里");
      System.out.println("list=" + list);
      System.out.println(list.lastIndexOf("拉里"));
//      Object remove(int index):移除指定index位置的元素,并返回此元素
      list.remove(0);
      System.out.println("list=" + list);
//      Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
      list.set(1, "玛丽");
      System.out.println("list=" + list);
//      List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
      // 注意返回的子集合 fromIndex <= subList < toIndex
      List returnlist = list.subList(0, 2);
      System.out.println("returnlist=" + returnlist);
    }
}在开发中,需要线程同步安全时,考虑使用 Vector
public class ListExercise {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
      /*
      添加10个以上的元素(比如String "hello" ),在2号位插入一个元素"教育",
      获得第5个元素,删除第6个元素,修改第7个元素,在使用迭代器遍历集合,
      要求:使用List的实现类ArrayList完成。
         */
      List list = new ArrayList();
      for (int i = 0; i < 12; i++) {
            list.add("hello" + i);
      }
      System.out.println("list=" + list);

      //在2号位插入一个元素"教育"
      list.add(1, "教育");
      System.out.println("list=" + list);
      //获得第5个元素
      System.out.println("第五个元素=" + list.get(4));
      //删除第6个元素
      list.remove(5);
      System.out.println("list=" + list);
      //修改第7个元素
      list.set(6, "三国演义");
      System.out.println("list=" + list);

      //在使用迭代器遍历集合
      Iterator iterator = list.iterator();
      while (iterator.hasNext()) {
            Object obj =iterator.next();
            System.out.println("obj=" + obj);
      }
    }
}
</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 的底层操作机制


public class ListFor {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {

      //List 接口的实现子类 Vector LinkedList
      //List list = new ArrayList();
      //List list = new Vector();
      List list = new LinkedList();

      list.add("jack");
      list.add("tom");
      list.add("鱼香肉丝");
      list.add("北京烤鸭子");

      //遍历
      //1. 迭代器
      Iterator iterator = list.iterator();
      while (iterator.hasNext()) {
            Object obj =iterator.next();
            System.out.println(obj);

      }

      System.out.println("=====增强for=====");
      //2. 增强for
      for (Object o : list) {
            System.out.println("o=" + o);
      }

      System.out.println("=====普通for====");
      //3. 使用普通for
      for (int i = 0; i < list.size(); i++) {
            System.out.println("对象=" + list.get(i));
      }
    }
}12.7.3 LinkedList的增删改查案例

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 接口的实现类有:public class Vector<E>
    extends AbstractList<E>
    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 接口的常用方法举例

protected Object[] elementData;12.10.3 HashSet 底层机制说明

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


public synchronized E get(int index) {
    if (index >= elementCount)
      throw new ArrayIndexOutOfBoundsException(index);
    return elementData(index);
}
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; iNode -> 加入table , 就算是增加了一个size++         */      for(int i = 1; i
页: [1]
查看完整版本: 第 12 章 集合