每日筑基之集合一

一.集合体系结构

今天主要学习Collection集合体系(一口吃不成一个大胖子)

**List集合:有序,可重复   **Set集合:无序,不重合

1、单列集合的顶级接口是谁?双列集合的顶级接口是谁?

Collection: 每个元素都是一个值 Map: 每个元素都包含两个值

二.Collection

Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。

1.Collection的常见方法

2.Collcetion集合的遍历方式

(1)迭代器--iterator()


遍历1: 送代器Iterator
    单列集合专用遍历方式

Iterator相关方法
    Iterator<E> iterator() 获取迭代器对象,默认指向第一个元素
    boolean hasNext() 断当前位置是否有元素可以取出 (有返回true,没有返回false)
    E next() 返回当前位置的元素,并将送代器后移一位(如果没有元素可以取出了还继续取,会报NoSuchElementException)

固定格式
    Iterator<String> iterator  = list.iterator();
    while (iterator.hasNext()) {
        String s = iterator.next();
    }
*/
public class Demo3 {
    public static void main(String[] args) {
        //1. 准备一个集合
        Collection<String> collection = new ArrayList<>();
        collection.add("java");
        collection.add("python");
        collection.add("c++");
        collection.add("c#");

        //2. 获取迭代器对象
        Iterator<String> iterator = collection.iterator();

        //3. 使用迭代器遍历
        //3.1 使用while,判断是否有下个元素
        while(iterator.hasNext()) {
            //3.2 获取下个元素
            String str = iterator.next();
            System.out.println(str);
        }
    }
}

(2)增强for


/*
遍历2: 增强for循环
    数组和集合都可以使用

相关格式
    for(元素数据类型 变量名 : 数组或者集合){
        操作变量
    }

注意
    1. 在增强for循环中修改数据, 是不会影响数据源的(底层会创建临时变量,来记录容器中的数据)
    2. 增强for遍历集合,底层是迭代器遍历集合的逻辑
    3. 增强for遍历数组,底层是普通for循环的逻辑
*/
public class Demo4 {
    public static void main(String[] args) {
        //1. 准备一个集合
        Collection<String> collection = new ArrayList<>();
        collection.add("java");
        collection.add("python");
        collection.add("c++");
        collection.add("c#");

        //2. 使用增强for循环遍历
        for (String s : collection) {
            System.out.println(s);
        }


        //增强for循环也可以遍历数组
        int[] arr = {1,2,3};
        for (int i : arr) {
            System.out.println(i);
        }

    }
}

(3)Lambda表达式遍历集合

3.集合的并发修改异常

使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。

由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误

怎么保证遍历集合同时删除数据时不出bug?

使用迭代器遍历集合:但用迭代器自己的删除方法删除数据即可。

使用增强for循环遍历集合:无法解决这个问题 使用普通for循环遍历集合:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i --操作。

4.List集合(有序,可重复)

(1)list集合特有的方法

因为list集合支持索引,所以多了许多list特有的方法


/*
List系列集合的特点
    有序的, 可重复

List集合支持索引,所以提供了很多通过索引操作元素的方法
    void add(int index,E e) 在此集合中的指定位置插入指定的元素
    E remove(int index) 删除指定索引处的元素,返回被删除的元素 (一般不接收)
    E set(int index,E e) 修改指定索引处的元素,返回被修改的元素(一般不接收)
    E get(int index) 返回指定索引处的元素
*/
public class Demo1 {
    public static void main(String[] args) {
        //多态方式创建list集合
        List<String> list = new ArrayList<String>();
        list.add("关羽"); //0
        list.add("张飞"); //1
        list.add("赵云"); //3
        list.add("刘备"); //4
        //void add(int index,E e) 在此集合中的指定位置插入指定的元素
        list.add(2,"曹操"); //2
        System.out.println(list);
        //E remove(int index) 删除指定索引处的元素,返回被删除的元素 (一般不接收)
        list.remove(4);
        System.out.println(list);
        //E set(int index,E e) 修改指定索引处的元素,返回被修改的元素(一般不接收)
        list.set(1,"张飞飞");
        System.out.println(list);
        //E get(int index) 返回指定索引处的元素

        System.out.println(list.get(1));
        //System.out.println(list);
    }
}

(2)遍历方式

与Collecction的遍历方式一样

5.ArrayList集合

(1)底层原理

基于数组实现

(2)特点

查询速度快,但是删除效率低

(3)ArrayList的使用场景

根据随机索引查询数据时,或者数据量不是很大时

6.LinkedList

(1)底层原理

基于双链表实现     

 (2)list集合特有的方法

(3)使用场景

比如设计队列


/*
LinkedList
    底层数据结构:
        基于双向链表实现(内存地址不连续,每个元素记录自己的前后元素)
    特点:
        1. 查询速度慢
        2. 增删效率高
        3. 对于首尾元素进行增删改查的速度都是极快的
    应用场景:
        1. 用来设计队列(两端开口,类似于一个管道,先进先出)
            只操作首尾元素, 尾部添加, 首部删除
        2. 用来设计栈(一段开口,类似于弹夹,先进后出)
*/
public class Demo4 {

    public static void main(String[] args) {
        //makeQueue();
        makeStack();
    }

    /*
        队列: 两端开口,特点是先进先出(排队)
        从队列后端入队列:  addLast 方法
        从队列前端出队列:  removeFirst方法
    */
    public static void makeQueue() {

        LinkedList<String> queue = new LinkedList<>();

        //排队买票 (入队)
        queue.addLast("1号顾客"); //1号顾客
        queue.addLast("2号顾客"); //1号顾客,2号顾客
        queue.addLast("3号顾客"); //1号顾客,2号顾客,3号顾客
        queue.addLast("4号顾客"); //1号顾客,2号顾客,3号顾客,4号顾客
        queue.addLast("5号顾客"); //1号顾客,2号顾客,3号顾客,4号顾客,5号顾客

        System.out.println(queue);

        System.out.println("--------------");

        //放票-出对
        String str1 = queue.removeFirst();
        System.out.println(str1);
        String str2 = queue.removeFirst();
        System.out.println(str2);
        String str3 = queue.removeFirst();
        System.out.println(str3);

        System.out.println(queue);
    }

    /*
        栈: 顶端开口的结构,特点是先进后出
        进栈/压栈: push方法(底层封装了addFirst 方法)
        出栈/弹栈: pop方法底 (底层封装了removeFirst方法)
    */
    public static void makeStack() {
        //创建LinkedList
        LinkedList<String> stack = new LinkedList<>();
        //压栈(push):将数据存入栈中
        stack.push("关羽");
        stack.push("张飞");
        stack.push("赵云");
        System.out.println(stack);
        System.out.println("-------------------");
        //弹栈(pop):将栈顶数据移除
        String str1 = stack.pop();
        System.out.println(str1); //赵云
        System.out.println(stack);
    }
}

三.双列集合--set

特点:无序,不可重复

1.HashSet



/*
哈希值
    就是一int值,Java每个对象都可以通过hashCode方法,获取自己的哈希值

哈希值特点
    同一个对象多次调用hashCode方法,返回的哈希值是相同的;
    不同的对象,他们哈希值大几率不相同,但是也有可能会相同(哈希碰撞)
    Object的hashCode方法根据"对象地址值"计算哈希值,子类重写后的hashCode方法可以根据"对象属性值"计算哈希值

使用场景
    HashSet集合判定两个对象的标准就是两个对象的hash值是否一致, 因此我们经常重写hashcode实现集合中对象去重
*/
public class Demo2 {
    public static void main(String[] args) {
//        //1、创建Student对象,获取对象的hash值
//        Student student = new Student("张三", 18);
//        int code1 = student.hashCode();
//        int code2 = student.hashCode();
//        //同一个对象多次调用hashCode方法,返回的哈希值是相同的;
//        System.out.println(code1);
//        System.out.println(code2);
//        //2、不同的对象,他们哈希值大几率不相同,但是也有可能会相同(哈希碰撞)
//        Student student2 = new Student("张三", 18);
//        int code3 = student2.hashCode();
//        System.out.println(code3);

        //通过HashSet集合,存储学生数据(去重)
        HashSet<Student> set = new HashSet();
        //构造几个学生对象,存入到set
        Student student1 = new Student("张三", 18);
        Student student2 = new Student("李四", 28);
        Student student3 = new Student("张三", 18);

        System.out.println(student1.hashCode());
        System.out.println(student3.hashCode());

        System.out.println(student1.toString());

        System.out.println(student3.toString());

        set.add(student1);
        set.add(student2);
        set.add(student3);
        //打印set中的数据
        System.out.println(set);
    }
}

class Student {

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @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);
    }

}

2.TreeSet

(1)底层原理

(2)排序



/*
TreeSet 可排序、不重复、无索引
    底层基于红黑树实现排序,排序规则认为属性是相同的对象则不存

TreeSet的排序
    对于数值型Integer、Double,默认按照数值升序排列;
    对于String类型数据,默认按照字典排序
    对于自定义类,默认是无法排序的,需要我们指定排序规则
        自然排序:自定义类实现Comparable接口,重写compareTo方法,指定排序规则
        比较器排序:写在TreeSet构造参数中传递Comparator比较器对象,重写compare方法,指定排序规则
需求
    使用TreeSet存储教师对象,重复对象不存,并且用两种方式按照年龄升序排列
*/
public class Demo4 {

    public static void main(String[] args) {
        //创建TreeSet
        Set<Teacher> treeSet = new TreeSet<>(new Comparator<Teacher>() {
            @Override
            public int compare(Teacher o1, Teacher o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        //添加学生
        treeSet.add(new Teacher("张三", 19));
        treeSet.add(new Teacher("李四", 18));
        treeSet.add(new Teacher("王五", 20));
        treeSet.add(new Teacher("赵六", 17));
        treeSet.add(new Teacher("赵六", 17));

        //打印
        for (Teacher teacher : treeSet) {
            System.out.println(teacher);
        }
    }
}

class Teacher  {


    private String name;
    private int age;

    public Teacher() {
    }

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Teacher teacher = (Teacher) o;
        return age == teacher.age && Objects.equals(name, teacher.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

三.使用场景

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值