Java集合详解(List和Set)

简介: Java集合讲解!入门学习!

一. 集合的诞生

集合是为了弥补数组的不足而存在。

集合相对于数组优势在于:a.集合的长度可以动态改变;b.集合中能够存放多种类型的数据。

在这里插入图片描述

二. 集合的家族

Collection接口是所有单值集合的父接口

List接口与Set接口的区别:

在这里插入图片描述

一个集合类的对象就一个集合。

Collection中常用的方法

方法名 描述
add(E e) 确保此 collection 包含指定的元素(可选操作)。
clear() 移除此 collection 中的所有元素(可选操作)。
contains(Object o) 如果此 collection 包含指定的元素,则返回true
equals(Object o) 比较此 collection 与指定对象是否相等
isEmpty() 如果此 collection 不包含元素,则返回true。
iterator() 返回在此 collection 的元素上进行迭代的迭代器。
remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话。
size() 返回此 collection 中的元素数。
toArray() 返回包含此 collection 中所有元素的数组。

1、List集合有序,可重复)

ArrayList:LinkedList:

①ArrayList: 底层数据结构是数组,查询快,增删慢

②LinkedList: 底层数据结构是链表,查询慢,增删快

两者共同缺点: 线程不安全,效率高


Vector:

①优点: 底层数据结构是数组,查询快,增删慢。

②缺点: 线程安全,效率低

小结:底层数据结构特点决定其性能特性

---

2、Set集合—(无序,唯一)

  • Set接口是Collection的子接口,表示元素无序且不可重复的集合。

在这里插入图片描述
(1)HashSet:

底层数据结构是哈希表。(无序,唯一)

如何来保证元素唯一性?

1、依赖两个方法:hashCode()和equals()
2、HashSet底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。


具体实现唯一性的比较过程:

1.存储元素时首先会使用hash()算法函数生成一个int类型hashCode散列值,然后已经的所存储的元素的hashCode值比较,如果hashCode不相等,肯定是不同的对象。
2.hashCode值相同,再比较equals方法。
3.equals相同,对象相同。(则无需储存)


(2)LinkedHashSet:

底层数据结构是链表和哈希表 (FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一
LinkedHashSet底层数据结构采用链表和哈希表共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性。线程不安全,效率高。


(3)TreeSet:

底层数据结构是红黑树。(唯一,有序)

如何保证元素排序的呢?

1、自然排序

2、比较器排序


如何保证元素唯一性的呢?

1、根据比较的返回值是否是0来决定

2、TreeSet底层数据结构采用红黑树来实现,元素唯一且已经排好序;唯一性同样需要重写hashCode和equals()方法,二叉树结构保证了元素的有序性。根据构造方法不同,分为自然排序(无参构造)和比较器排序(有参构造)

3、自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储;

4、比较器排序要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;


TreeSet实践案例

①在元素类中定义排序规则

import java.util.TreeSet;

//创建学生类实践
public class Student implements Comparable<Student> {
    private String stuNum;
    private String stuName;
    private String stuSex;
    private int stuAge;

    public Student(String stuNum, String stuName, String stuSex, int stuAge) {
        this.stuNum = stuNum;
        this.stuName = stuName;
        this.stuSex = stuSex;
        this.stuAge = stuAge;
    }

    public String getStuNum() {
        return stuNum;
    }

    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public String getStuSex() {
        return stuSex;
    }

    public void setStuSex(String stuSex) {
        this.stuSex = stuSex;
    }

    public int getStuAge() {
        return stuAge;
    }

    public void setStuAge(int stuAge) {
        this.stuAge = stuAge;
    }

    @Override
    public String toString() {
        return "Student{" +
                "编号'" + stuNum + '\'' +
                ", 姓名='" + stuName + '\'' +
                ", 性别='" + stuSex + '\'' +
                ", 年龄=" + stuAge +
                '}';
    }

        //重写里面的compareTo()方法
    @Override
    public int compareTo(Student o) {
        // compareTo 的参数o表示集合中已经存在的元素
        return this.stuAge - o.stuAge;
    }

    //案例
    public static void main(String[] args) {
        //TreeSet<Student> ts = new TreeSet<Student>();

        TreeSet<Student> ts =new TreeSet<Student>();
        Student s1 = new Student("10001", "Lilei", "M", 20);
        Student s2 = new Student("10002", "HanMeimei", "F", 19);
        Student s3 = new Student("10003", "Lily", "F", 21);
        Student s4 = new Student("10004", "Tom", "M", 22);
        ts.add(s1);    // [s1]
        ts.add(s2); // [s2,s1]
        ts.add(s3); // [s2,s1,s3]
        ts.add(s4); // [s2,s1,s3,s4]
        System.out.println(ts);
    }
}

  • 比较器中我们按年龄排序,输出结果也是按年龄排序
[Student{编号'10002', 姓名='HanMeimei', 性别='F', 年龄=19}, 
Student{编号'10001', 姓名='Lilei', 性别='M', 年龄=20},
 Student{编号'10003', 姓名='Lily', 性别='F', 年龄=21},
  Student{编号'10004', 姓名='Tom', 性别='M', 年龄=22}]

给TreeSet集合指定比较器(未继承接口)

import java.util.Comparator;
import java.util.TreeSet;

public class Student {
    private String stuNum;
    private String stuName;
    private String stuSex;
    private int stuAge;

    public Student(String stuNum, String stuName, String stuSex, int stuAge) {
        this.stuNum = stuNum;
        this.stuName = stuName;
        this.stuSex = stuSex;
        this.stuAge = stuAge;
    }

    public String getStuNum() {
        return stuNum;
    }

    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public String getStuSex() {
        return stuSex;
    }

    public void setStuSex(String stuSex) {
        this.stuSex = stuSex;
    }

    public int getStuAge() {
        return stuAge;
    }

    public void setStuAge(int stuAge) {
        this.stuAge = stuAge;
    }

    @Override
    public String toString() {
        return "Student{" +
                "编号'" + stuNum + '\'' +
                ", 姓名='" + stuName + '\'' +
                ", 性别='" + stuSex + '\'' +
                ", 年龄=" + stuAge +
                '}';
    }

    //案例
    public static void main(String[] args) {

        //切记这里是Comparator
        Comparator<Student> cptr = new Comparator<Student>() {
            //o1表示向集合中新增的元素,o2表示集合中已经存在的元素
            public int compare(Student o1, Student o2) {
                int i = o1.getStuAge() - o2.getStuAge();
                return i;
            }
        };
        
        TreeSet<Student> ts = new TreeSet<Student>(cptr);
        Student s1 = new Student("10001", "Lilei", "M", 20);
        Student s2 = new Student("10002", "HanMeimei", "F", 19);
        Student s3 = new Student("10003", "Lily", "F", 21);
        Student s4 = new Student("10004", "Tom", "M", 22);
        ts.add(s1);    // [s1]
        ts.add(s2); // [s2,s1]
        ts.add(s3); // [s2,s1,s3]
        ts.add(s4); // [s2,s1,s3,s4]
        System.out.println(ts);
    }
}

  • 输出结果
[Student{编号'10002', 姓名='HanMeimei', 性别='F', 年龄=19}, 
Student{编号'10001', 姓名='Lilei', 性别='M', 年龄=20},
 Student{编号'10003', 姓名='Lily', 性别='F', 年龄=21},
  Student{编号'10004', 姓名='Tom', 性别='M', 年龄=22}]

注意:小编我在编辑过程将上例中Comparator打错成Comparable导致自定义程序无法出结果,希望大家用比较器也多注意。


补充:Comparable和Comparator区别

  • 对于Comparable接口来说,被比较对象所属的类需要直接实现Comparable接口,实现该接口的类被赋予一个自然顺序,而且该自然顺序只有一个,而Comparator是一个比较器接口,被比较对象所属的类不需要直接实现该接口,可以单独写一个比较器类实现该接口,作为比较对象的一个比较器,对于一个类来说,可以实现多个比较器。
  • Comparator可以选择对null进行比较,而Comparable不可以。主要是因为Comparator的比较对象都是compare方法的参数,而Comparable的比较方法compareTo方法需要对象来调用,而对象为null时(null.compareTo(obj)),会出现异常。

Lambda表达式

是JDK1.8新增的表达式语法,实际上就是一个语法糖,用于对接口中的方法进行实现。

代码修改对比

        //切记这里是Comparator
        Comparator<Student> cptr = new Comparator<Student>() {
            //o1表示向集合中新增的元素,o2表示集合中已经存在的元素
            public int compare(Student o1, Student o2) {
                int i = o1.getStuAge() - o2.getStuAge();
                return i;
            }
        };
        TreeSet<Student> ts = new TreeSet<Student>(cptr);

Lambda表达式的应用

 //Lambda表达式
        TreeSet<Student> ts2 = new TreeSet<Student>((o1,o2)->o1.getStuAge()-o2.getStuAge());

输出结果一样,但是格式更加简洁


May you find the work you are willing to devote to and love it.

非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

愿你们奔赴在自己的热爱里!

目录
相关文章
|
4月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
285 100
|
4月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
317 101
|
4月前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
3月前
|
存储 算法 安全
Java集合框架:理解类型多样性与限制
总之,在 Java 题材中正确地应对多样化与约束条件要求开发人员深入理解面向对象原则、范式编程思想以及JVM工作机理等核心知识点。通过精心设计与周密规划能够有效地利用 Java 高级特征打造出既健壮又灵活易维护系统软件产品。
116 7
|
3月前
|
存储 Java 索引
(Python基础)新时代语言!一起学习Python吧!(二):字符编码由来;Python字符串、字符串格式化;list集合和tuple元组区别
字符编码 我们要清楚,计算机最开始的表达都是由二进制而来 我们要想通过二进制来表示我们熟知的字符看看以下的变化 例如: 1 的二进制编码为 0000 0001 我们通过A这个字符,让其在计算机内部存储(现如今,A 字符在地址通常表示为65) 现在拿A举例: 在计算机内部 A字符,它本身表示为 65这个数,在计算机底层会转为二进制码 也意味着A字符在底层表示为 1000001 通过这样的字符表示进行转换,逐步发展为拥有127个字符的编码存储到计算机中,这个编码表也被称为ASCII编码。 但随时代变迁,ASCII编码逐渐暴露短板,全球有上百种语言,光是ASCII编码并不能够满足需求
191 4
|
5月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
320 23
|
4月前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
5月前
|
存储 缓存 安全
Java集合框架(三):Map体系与ConcurrentHashMap
本文深入解析Java中Map接口体系及其实现类,包括HashMap、ConcurrentHashMap等的工作原理与线程安全机制。内容涵盖哈希冲突解决、扩容策略、并发优化,以及不同Map实现的适用场景,助你掌握高并发编程核心技巧。
|
5月前
|
存储 NoSQL Java
Java Stream API:集合操作与并行处理
Stream API 是 Java 8 提供的集合处理工具,通过声明式编程简化数据操作。它支持链式调用、延迟执行和并行处理,能够高效实现过滤、转换、聚合等操作,提升代码可读性和性能。
|
5月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。

热门文章

最新文章