集合进阶——集合体系结构

38 阅读5分钟

单列集合Collection

  • 红色的是接口,蓝色的是实现类
  • Vector已经淘汰了
  • List系列集合:添加的元素是有序(存和取出来的元素是一样的)、可重复、有索引
  • Set系列集合:添加的元素是无序、不重复、无索引

image.png

Collection中基本方法

image.png

package collectiondemo;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection是一个接口,不能直接创建它的对象
        所以我们学习他的方法时,只能创建它实现类的对象。如ArrayList

        Collection<String> coll = new ArrayList<>();
        这样利用多态创建对象是为了学习其中的方法,正常情况下直接用以前方法创建就行

        //1.添加元素
        //往List系列添加元素永远返回true
        //由于Set系列不允许重复,所以有可能返回false
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        System.out.println(coll);//[aaa, bbb, ccc]

        //2.清空集合
        //coll.clear();

        //3.删除元素
        //因为Collection里面定义的是共性的方法,但是Set系列没有索引,所以只能通过元素的对象删除
        coll.remove("aaa");
        System.out.println(coll);//[bbb, ccc]

        4.判断集合中是否包含给定对象
        底层依赖equals方法判断是都存在,所以如果集合中存储的是自定义对象,也想通过contains方法判断是否包含,要重写equals方法。
        对于 String 类型:String 类已经重写了 equals 方法,比较的是内容
        对于自定义对象:如果没有重写 equals 方法,默认比较的是内存地址

        Boolean flag = coll.contains("aaa");
        System.out.println(flag);//false
        flag = coll.contains("bbb");
        System.out.println(flag);//true
        
        //5.判断集合是否为空
        flag = coll.isEmpty();
        System.out.println(flag);//false

        //6.获取集合的长度
        int len = coll.size();
        System.out.println(len);//2

    }
}

Colection的遍历方式

  • 普通的for循环用不了,因为Set系列没有索引,而Collection要包含两者共性。

迭代器遍历

  • 迭代器不依赖索引
  • 如果迭代器指向集合最后+1的位置,在使用next方法会报NoSuchElementException
  • 迭代器遍历完毕,指针不会复位
  • 循环中只能使用一次next方法

image.png

package collectiondemo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        //迭代器遍历

        //1.创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");

        //2.使用集合对象去调用iterator方法获取迭代器对象
        //迭代器就好比是一个箭头,默认指向集合的0索引处
        Iterator<String> it = coll.iterator();

        //3.利用循环不断的获取每一个元素
        //next方法不仅获取元素,而且还移动指针(迭代器)
        while (it.hasNext()) {
            String str = it.next();
            System.out.println(str);
        }
    }
}
  • 迭代器遍历时,不能用集合的方法进行增加或删除,如果实在要删除,可以用迭代器的remove方法,但是如果想添加,是没有办法的。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");

Iterator<String> it = list.iterator();
while(it.hasNext()) {
    String s = it.next();
    if("A".equals(s)) {
        list.remove("A"); // ❌ 并发修改异常!
        // 正确做法:使用迭代器的remove方法
        it.remove(); // ✅
    }
}

增强for遍历

image.png

Lambada表达式遍历

package collectiondemo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;

public class LambdaDemo {
    public static void main(String[] args) {
        //1.定义一个集合
        Collection<String> coll = new ArrayList<>();
        //2.添加一些元素
        coll.add("xzx");
        coll.add("xs");
        coll.add("xss");
        //3.使用匿名内部类的形式
        coll.forEach(new Consumer<String>(){
            @Override
            public void accept(String t) {
                System.out.println(t);
            }
        });
        //4.使用Lambda简化匿名内部类
        coll.forEach((String t)->{
                System.out.println(t);
        });
        //5.根据Lambda简化规则继续简化
        coll.forEach(t -> System.out.println(t));

        //Idea自动简化
        coll.forEach(System.out::println);
    }

}

List集合的特有方法

image.png

  • 在删除的时候会有两种删除方法,一个形参是int index 一个是Object o
  • 下面第一次删除的时候,因为直接放到括号里的是1,默认int,所以会自动调用删除索引的remove方法,所以会把2删掉。
image.png

List集合的遍历方式

  • 迭代器遍历
  • 列表迭代器遍历
  • 增强for循环
  • Lambda表达式遍历
  • 普通for循环(使用list.size和get方法)
public class ListDemo2 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //额外添加了一个方法,在遍历过程中,可以添加元素。
        ListIterator<String> it = list.listIterator();
        while(it.hasNext()){
            String s = it.next();
            if("a".equals(s)){
                it.add("lalala");
            }
        }
        System.out.println(list);
    }
}

image.png

Set系列集合

特点

  • 无序:存和取的顺序不一致
  • 无重复:可以去除重复
  • 无索引:不能使用普通for循环来遍历

Set集合的实现类

  • HashSet:无序,不重复,无索引
  • LinkedHashSet:有序,不重复,无索引
  • TreeSet:可排序,不重复,无索引
package setdemo;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;

public class SetDemo1 {
    static void main(String[] args) {
        //1.实现一个Set集合的对象
        //Set是一个接口,不能实例化,要创建它实现类的对象。
        Set<String> set = new HashSet<>();

        //2.添加元素
        boolean r1 = set.add("aaa");
        boolean r2 = set.add("aaa");
        set.add("bbb");
        set.add("ccc");
        System.out.println(r1);//true
        System.out.println(r2);//false
        System.out.println(set);//[aaa, ccc, bbb]

        //3.迭代器遍历
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        //4.增强for遍历
        for (String str : set) {
            System.out.println(str);
        }

        //5.lambda表达式,先写匿名内部类
        //set.forEach(new Consumer<String>() {
        //    @Override
        //    public void accept(String s) {
        //        System.out.println(s);
        //    }
        //});
        //简化Lambda表达式
        set.forEach( s-> System.out.println(s));

    }
}

HashSet

  • HashSet集合底层采取哈希表存储数据
  • 哈希表组成:数组+链表+红黑树(jdk8之前没有红黑树)
  • 哈希值:对象的整数表现形式

image.png

  • 没有重写HashCode方法的情况

image.png

  • 重写HashCode方法:Alt+Insert自动生成
  • String 类的 hashCode() 方法计算公式为:s[0]×31(n−1)+s[1]×31(n−2)+⋯+s[n−1]s[0]×31(n−1)+s[1]×31(n−2)+⋯+s[n−1]所以下面两个字符串产生了哈希碰撞
    image.png

HashSet添加元素

  • 加载因子用来进行数组扩容,16*0.75=12,数组长度达到12的时候就会扩容到原来的两倍,即32
  • 当链表长度超过8,而且数组长度大于等于64的时候,自动转化成红黑树

image.png

LinkHashSet

image.png

TreeSet

1.不重复,无索引,可排序

2.可排序:按照元素的默认规则(由小到大)排序

3.TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查效果都较好。

  • TreeSet的遍历
package treesetdemo;

import java.util.Iterator;
import java.util.TreeSet;
import java.util.function.Consumer;

public class TreeSetDemo1 {
    static void main(String[] args) {
        //利用TreeSet存取整数

        //1,创建TreeSet集合对象
        TreeSet<Integer> ts =  new TreeSet<>();

        //2.添加元素
        ts.add(4);
        ts.add(5);
        ts.add(3);
        ts.add(2);
        ts.add(1);

        //3.打印集合
        System.out.println(ts);//[1, 2, 3, 4, 5]

        //4.遍历集合
          //迭代器
        Iterator<Integer> it = ts.iterator();
        while(it.hasNext()){
            Integer num = it.next();
            System.out.println(num);
        }

          //增强for循环
        for (Integer i : ts) {
            System.out.println(i);
        }

          //lambda表达式,先写匿名内部类
        ts.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer i) {
                System.out.println(i);
            }
        });
          //简化匿名内部类
        ts.forEach( i-> System.out.println(i));
    }
}
  • 自定义对象的排序规则

image.png