Collection集合

概念:

集合是java中提供的一种容器,可以用来存储多个数据

集合和数组的区别:
  • 数组的长度是固定的,集合的长度是可变的。
  • 数组中存储的是同一类型的元素,可以存储任意类型数据。集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类型。集合的底层也是数组。
  • 集合底层是数组,在创建集合的时,会创建一个长度为10的数组,如果长度不够就会自动扩容原来数组长度的1.5倍,也就是15,然后将原数组拷贝的数据拷贝到长度15的数组里。
集合的体系结构:

请添加图片描述

Collection:

是单列集合的顶层接口,JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现

创建对象方式:

多态的方式
具体的实现类ArrayList

Collection常用方法:
方法名说明
boolean add(E e)添加元素
boolean remove(Object o)从集合中移除指定的元素
boolean removeIf(Object o)根据条件进行移除
void clear()清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中元素的个数
    public static void main(String[] args) {
        Collection<String> arrayList = new ArrayList<>();
        // 添加
        arrayList.add("itzhuzhu");
        arrayList.add("hehe");
        arrayList.add("今天过生日");

        // 删除
        System.out.println(arrayList.remove("itzhuzhu"));
        System.out.println(arrayList.remove("这里删除一段不存在的看一下返回的结果"));

        // 根据条件删除
        // removeIf底层会遍历集合,s代表每个元素,true删除,false不删除
        arrayList.removeIf((String s) -> {
            return s.length() == 4;
        });

        // 清空集合所有元素
        arrayList.clear();

        // 判断集合中是否存在指定的元素
        System.out.println("contains: " + arrayList.contains("hehe"));

        // 判断集合是否为空
        System.out.println("isEmpty: " + arrayList.isEmpty());

        // 返回集合的长度
        System.out.println("arrayList:" + arrayList.size());
        System.out.println(arrayList);
    }
iterator:
  • iterator是迭代器,集合专属遍历方式
  • 迭代器原理,默认指向0索引,依次按照需求操作,但是每次都会先–,再操作,对比fori循环先++,可以解决相同邻近元素无法删除操作。

循环执行:

  1. 先根据当前位置判断有没有下一个
  2. 获取当前位置的元素,再指向下一个

为什么要用迭代器:

在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口 java.util.Iterator 。

迭代器怎么获取:

 Iterator 对象 = 集合对象.iterator()

迭代器的实现原理

  • 当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。
  • Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。

在这里插入图片描述

常用方法:

方法名说明
Iterator iterator()创建迭代器,默认指向0索引​
boolean hasNext()判断当前位置是否有元素可以被取出
​E next()获取当前位置的元素,将迭代器对象移向下一个索引位置
void remove()删除迭代器对象当前指向的元素
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> arrayList = new ArrayList<>();

        //添加元素
        arrayList.add("hello");
        arrayList.add("world");
        arrayList.add("world");

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

        while (iterator.hasNext()) {
            String next = iterator.next();
            if ("world".equals(next)) {
        /**  不使用remove要手动去判断,当两个相邻的元素一样就会删除不了,因为循环判断以后就会做++,
             集合会自动加减长度,假如索引1和2都是a,那么删除了索引1,集合就会把索引2的a挪到1
        */
                iterator.remove();
            }
            System.out.println("next = " + next);
        }
        System.out.println("arrayList = " + arrayList);
    }

增强for :
  • 增强for是JDK5之后出现的,其内部原理是一个Iterator迭代器
  • 实现Iterable接口的类才可以使用迭代器和增强for,只要单列集合才可以使用,双列的都不可以。
  • 简化数组和Collection集合的遍历

格式:

for(集合/数组中元素的数据类型 变量名 :  集合/数组名) {// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可}
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        list.add("f");

        for (String str : list) {
            // 在集合里修改第三方变量值可以实现,但是不会影响集合原来的值
            str = "hehe";
            System.out.println("str = " + str);
        }
        System.out.println("list = " + list);
    }
三种循环的使用场景:
  1. 需要操作索引就用普通for循环
  2. 只需要遍历使用增强for
  3. 遍历的过程中需要删除元素,用迭代器

代码演示:

 public static void main(String[] args) {
        // 我们学习Collection集合中的方法,编译看左边,我们使用的方法都是来自Collection接口
        // 多态
        // 接口            变量名 = new 实现类();
        Collection<String> coll = new ArrayList<>();
        // 1.boolean add​(E e) 往集合中添加一个元素
        coll.add("王宝强");
        coll.add("谢霆锋");
        coll.add("贾乃亮");
        coll.add("陈羽凡");
        System.out.println(coll);
        // 2.void clear​() 从此集合中删除所有元素
        // coll.clear();

        // 3.boolean contains​(Object o) 判断集合中是否包含指定的元素
        System.out.println(coll.contains("贾乃亮")); // true
        System.out.println(coll.contains("杜海涛")); // false

        // 4.boolean isEmpty​() 判断集合是否为空(没有元素),如果为空返回true
        System.out.println(coll.isEmpty());

        // 5.boolean remove​(Object o) 删除集合中的指定元素,如果删除返回true
        System.out.println(coll.remove("王宝强")); // true
        System.out.println(coll.remove("大郎")); // false

        // 6.int size​() 返回此集合中的元素数
        System.out.println(coll.size());
        System.out.println(coll);
        System.out.println("------");
        // 7.Object[] toArray​() 将集合转成数组
        Object[] objects = coll.toArray();
        for (int i = 0; i < objects.length; i++) {
            Object obj = objects[i];
            System.out.println(obj);
        }
    }
List集合:

有序集合,这里的有序指的是存取顺序
可以精确控制列表中每个元素的插入位置,可以通过整数索引访问元素,并搜索列表中的元素,与Set集合不同,列表通常允许重复的元素

常用的子类:

  1. ArrayList
  2. LinkedList

特点:

  1. 存取有序
  2. 可以重复
  3. 有索引
List集合的特有功能
方法名描述
void add(int index,E element)在此集合中的指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index,E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素

代码演示:

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        // void add(int index,E element)	在此集合中的指定位置插入指定的元素
        list.add(0,"a");
        list.add("b");
        list.add("c");
        list.add("a");

        // E remove(int index)	删除指定索引处的元素,返回被删除的元素
        list.remove(0);
        list.remove("b");
        System.out.println("list = " + list);

        // E set(int index,E element)	修改指定索引处的元素,返回被修改的元素
        list.set(1, "修改了索引1");

        // E get(int index)	返回指定索引处的元素
        System.out.println("索引1 = " + list.get(1));
        System.out.println("list = " + list);
    }
ArrayList:

底层是数组结构实现,查询快、增删慢

LinkedList集合的特有功能:

底层是双向链表结构实现,查询慢、增删快

方法名说明
public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public E getLast()返回此列表中的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
public E removeLast()从此列表中删除并返回最后一个元素
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        // public void addFirst(E e)	在该列表开头插入指定的元素
        list.addFirst("-a");

        // public void addLast(E e)	将指定的元素追加到此列表的末尾
        list.addLast("d");
        System.out.println("操作前:" + list);

        // public E getFirst()	返回此列表中的第一个元素
        System.out.println("第一个元素 :" + list.getFirst());

        // public E getLast()	返回此列表中的最后一个元素
        System.out.println("最后一个元素 : " + list.getLast());

        // public E removeFirst()	从此列表中删除并返回第一个元素
        System.out.println("删除第一个元素 : " + list.removeFirst());

        // public E removeLast()	从此列表中删除并返回最后一个元素
        System.out.println("删除最后一个元素() : " + list.removeLast());
        System.out.println("操作后 : " + list);
    }
Set集合:
  1. 不可重复
  2. 存取无序
  3. 无索引不能使用普通for循环遍历
TreeSet:
  1. 不可以存储重复元素
  2. 没有索引
  3. 可以将元素按照规则进行排序(使用TreeSet必须定义排序规则)
  4. TreeSet底层实现的是红黑树的数据结构

实现原理:
在这里插入图片描述

自然排序Comparable:

Comparator是一个比较接口,需求需要实现比较就要实现该接口,并重写compareTo方法

实现步骤:

  1. 使用空参构造创建TreeSet集合
    用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
  2. 自定义类实现Comparable接口
    自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
  3. 重写接口中的compareTo方法
    重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

返回值规则:

  1. 如果返回值为负数,表示当前存入的元素是较小值,存左边
  2. 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
  3. 如果返回值为正数,表示当前存入的元素是较大值,存右边
  4. 排序在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序,比如要按照字符串排序就可以用compare调用length排序

compareTo:

  • int compareTo​(T o):将此对象与指定的对象进行比较以获得顺序。 返回负整数,零或正整数,因为此对象小于,等于或大于指定对象。
  • 用于字符串与对象进行比较
  • 按字典顺序比较两个字符串

代码演示:
学生类

public class Student implements Comparable<Student> {
    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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        // 主要判断条件:按照年龄排序
        int result = this.age - o.age;
        //次要判断条件: 年龄相同时,按照姓名的字母顺序排序,这里的compareTo是String类的
        result = result == 0 ? this.name.compareTo(o.getName()) : result;
        return result;
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        // 创建集合
        TreeSet<Student> ts = new TreeSet<>();
        // 存入学生
        Student s1 = new Student("zhangsan", 28);
        Student s2 = new Student("lisi", 27);
        Student s3 = new Student("wangwu", 29);
        Student s4 = new Student("zhaoliu", 28);
        Student s5 = new Student("qianqi", 30);
        // 添加学生到集合
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        // 遍历集合
        for (Student student : ts) {
            System.out.println(student);
        }
    }
}
比较器排序comparator:

此比较器可以比较的对象类型,Comparator最常用的场景就是排序和分组

使用步骤:

创建TreeSet对象的时候传递comparator的实现类对象,重写compare方法,根据返回值进行排序

返回值规则:

  1. 如果返回值为负数,表示当前存入的元素是较小值,存左边
  2. 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
  3. 如果返回值为正数,表示当前存入的元素是较大值,存右边
  4. 排序在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序,比如要按照字符串排序就可以用compare调用length排序

代码演示:
老师类

public 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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

测试类

public class TeacherTest {
    public static void main(String[] args) {
        // 创建集合
        TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {

            @Override
            public int compare(Teacher o1, Teacher o2) {
                //o1表示现在要存入的那个元素 o2表示已经存入到集合中的元素
                //主要条件
                int result = o1.getAge() - o2.getAge();
                //次要条件
                result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                return result;
            }
        });
        // 存入老师
        Teacher s1 = new Teacher("zhangsan", 28);
        Teacher s2 = new Teacher("lisi", 27);
        Teacher s3 = new Teacher("wangwu", 29);
        Teacher s4 = new Teacher("zhaoliu", 28);
        Teacher s5 = new Teacher("qianqi", 30);

        // 添加老师到集合
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        // 遍历集合
        for (Teacher teacher : ts) {
            System.out.println(teacher);
        }
    }
}

排序总结:

排序的时候想好主要条件和次要提交条件,这样做比较严谨

HashSet:
  1. 底层数据结构是哈希表
  2. 存取无序
  3. 不可以存储重复元素
  4. 没有索引,不能使用普通for循环遍历
  5. 属于Set集合所以元素唯一
  6. 底层是哈希表结构的
哈希值:

哈希值是JDK根据对象的地址或者属性值,算出来的int类型的数值

获取哈希值:

Object类中的 public int hashCode():返回对象的哈希码值

哈希值的特点:

  1. 如果没有重写hashCode方法,那么是根据对象的地址值计算出的哈希值。
    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
    • 不同的对象的哈希值是不同的
  2. 如果重写hashCode方法,一般是通过对象的属性值计算出哈希值
    • 如果不同的对象属性值是一样的,那么计算出来的哈希值也是一样的
哈希表结构:

JDK1.8以前底层是数组+链表:

  1. 创建一个默认长度为16,加载因子(决定哈希表什么扩容)为0.75的数组,数组名为table
  2. 根据元素的哈希值跟数组的长度计算出应存入的位置
  3. 判断当前位置是否为null,如果是null直接存入
  4. 如果应存入的位置不为null,表示有元素,则调用equals方法比较属性值
  5. 如果一样,则不存,如果不一样,则存入数组,老元素挂在新元素下面

请添加图片描述

JDK1.8以后是数组+链表+红黑树:

节点个数少于等于8个就用(数组 + 链表),多于8个用(数组 + 红黑树)

请添加图片描述
练习:

创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合,HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

学生类:

public class Student {
    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);
    }

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

测试类:

public class StudentTest {
    public static void main(String[] args) {
        //创建HashSet集合对象
        HashSet<Student> hs = new HashSet<Student>();

        //创建学生对象
        Student s1 = new Student("韩信", 30);
        Student s2 = new Student("李白", 35);
        Student s3 = new Student("露娜", 33);
        Student s4 = new Student("露娜", 33);

        //把学生添加到集合
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        //遍历集合(增强for)
        for (Student s : hs) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzhuzhu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值