【JAVA学习之路 | 进阶篇】Set及其实现类与常用方法

简介: 【JAVA学习之路 | 进阶篇】Set及其实现类与常用方法

1.Set及其常用实现类

Set接口是java.util.Collection接口的子接口.用来存储一个一个的数据.后面学习到的Map接口则用来存储key-value键值对.

Set : 存储无序的,不可重复的数据
    |----->HashSet : 主要实现类 : 底层使用的是HashMap,即使用数组+单向链表+红黑树来存储。
        |----->LinkedSet : 是HashSet的子类,在其存储结构的基础上,增加了一组双向链表,用来记录添加                        
                           元素的先后顺序。即我们可以按照添加的顺序实现遍历.便于频繁查询工作。
    |----->TreeSet : 底层使用红黑树进行存储,可以按照添加的元素的指定属性的大小顺序来进行遍历.

2.Set中常用方法

即Collection接口中的15个抽象方法.没有新增的方法.

3.Set中无序性与不可重复性的理解

(1). 无序性 :并不等同于随机性.

添加元素的顺序与遍历元素的顺序不一致,是否能说明Set的无序性呢?其实是不可以的.因为可以看到,多次运行,遍历结果还是第一次的遍历元素的顺序.

@Test
    public void Test1() {
        Set set = new HashSet();
        //自动装箱
        set.add(12);
        set.add(34);
        set.add("hexua");
        set.add('a');
        //foreach循环
        for (Object obj : set) {
            System.out.println(obj);
        }
    }
 
控制台
//多次运行,都是这个顺序
a
34
12
hexua

无序性与添加的元素的位置有关.其并不像ArrayList是连续排列的.其是根据哈希函数算得的哈希值计算其在数组中的存储位置,因为该位置不是依次紧密排列的,表现为无序性.(学过数据结构的应该觉得比较好理解一点)


(2). 不可重复性 : 添加到Set元素中的元素不能相同.


其比较的标准是hashCode()得到的哈希值及equals()得到的boolean类型的结果.只有哈希值相等,而且equals()返回true,则判断元素已重复,所以不将该元素添加到Set中.


(3). 注 : 添加到HashSet/LinkedHashSet的元素的要求 : 必须重写Object类中的HashCode与equals方法.且二者需要保持一致性.

4.HashSet的底层结构

通过查看源码,发现HashSet的底层是通过HashMap来实现的.

public HashSet() {
        map = new HashMap<>();
    }

而HashMap的底层使用数组+单向链表+红黑树来存储.


例如add(12),通过hashCode方法可以算出一个哈希值,并将该元素放到该哈希值对应的位置存储.该位置存储的是元素的地址.接着后面add(23),add(34)...如果hashCode()算得某个位置,并且该位置已经存储了某个元素的地址(哈希冲突),那么第一个元素可以存储第二个元素的引用,从而构成了单链表.


重复性判断可以这样理解.hashCode()算出一个哈希值,找到该哈希值对应的位置,将该元素(A)与该位置对应的元素(B)(只有单元素情况)进行equals比较.如果相等,则返回,不加入到HashSet中,如果不相等,则原来的元素(B)存储该元素(A)的引用,即加入到HashSet中.如果哈希值对应的位置指向的一条单向链表,则将该元素与指向的一条单链表依次比较.

5.TreeSet的使用

(1). 查看源码发现,TreeSet底层是通过TreeMap实现,故TreeSet底层使用红黑树进行存储.


(2). 可以按照添加元素的指定的属性大小的顺序进行遍历.


(3). 要求 : 添加到TreeSet中的元素对象必须是同一类型,否则会报错.添加的元素需要考虑排序.自然排序or定制排序.即实现Comparable接口重写CompareTo方法或者实现Comparator接口重写Compare方法.


(4). 判断数据是否相等的标准.

  • 由于TreeSet并不是由数组+单向链表进行存储,所以不必重写hashCode与equals方法.
  • 标准考虑自然排序或者定制排序.由于TreeSet中不能存在相同的元素,所以后一个相同的元素不能被添加到TreeSet中.

自然排序(Comparable接口实现compareTo方法)以名字作为比较的依据.

public class Person implements Comparable{
    private String name;
    private int age;
 
    public Person() {
    }
 
    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
 
    @Override
    public int compareTo(Object o) {
        if (o instanceof Person) {
            Person p = (Person) o;
            return this.getName().compareTo(p.getName());
        }
        throw new RuntimeException("异常");
    }
}
 
@Test
    public void Test2() {
        Set set = new TreeSet();
        set.add(new Person("mahuateng", 50));
        set.add(new Person("dinglei", 51));
        set.add(new Person("liuqiangdong", 49));
        set.add(new Person("mayun", 52));
        for (Object obj : set) {
            //默认调用toString方法
            System.out.println(obj);
        }
    }
 
控制台
Person{name='dinglei', age=51}
Person{name='liuqiangdong', age=49}
Person{name='mahuateng', age=50}
Person{name='mayun', age=52}

定制排序(Comparator接口实现Compare方法)以名字作为比较的依据.

按住Ctrl+p,查看到可以放比较器实参.

@Test
    public void Test2() {
        Set set = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Person && o2 instanceof Person) {
                    Person p1 = (Person) o1;
                    Person p2 = (Person) o2;
                    return p1.getAge() - p2.getAge();
                }
                throw new RuntimeException();
            }
        });
        set.add(new Person("mahuateng", 50));
        set.add(new Person("dinglei", 51));
        set.add(new Person("liuqiangdong", 49));
        set.add(new Person("mayun", 52));
        for (Object obj : set) {
            System.out.println(obj);
        }
    }
 
控制台
Person{name='liuqiangdong', age=49}
Person{name='mahuateng', age=50}
Person{name='dinglei', age=51}
Person{name='mayun', age=52}
目录
打赏
0
1
1
0
6
分享
相关文章
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
77 0
Java 类和对象
本文介绍了Java编程中类和对象的基础知识,作为面向对象编程(OOP)的核心概念。类是对象的蓝图,定义实体类型;对象是具体实例,包含状态和行为。通过示例展示了如何创建表示汽车的类及其实例,并说明了构造函数、字段和方法的作用。同时,文章还探讨了访问修饰符的使用,强调封装的重要性,如通过getter和setter控制字段访问。最后总结了类与对象的关系及其在Java中的应用,并建议进一步学习继承等概念。
|
2月前
|
《从头开始学java,一天一个知识点》之:输入与输出:Scanner与System类
你是否也经历过这些崩溃瞬间?三天教程连`i++`和`++i`都说不清,面试时`a==b`与`equals()`区别大脑空白,代码总是莫名报NPE。这个系列就是为你打造的Java「速效救心丸」!每天1分钟,地铁通勤、午休间隙即可学习。直击高频考点和实际开发中的“坑位”,拒绝冗长概念,每篇都有可运行代码示例。涵盖输入输出基础、猜数字游戏、企业编码规范、性能优化技巧、隐藏技能等。助你快速掌握Java核心知识,提升编程能力。点赞、收藏、转发,助力更多小伙伴一起成长!
49 19
重学Java基础篇—类的生命周期深度解析
本文全面解析了Java类的生命周期,涵盖加载、验证、准备、解析、初始化、使用及卸载七个关键阶段。通过分阶段执行机制详解(如加载阶段的触发条件与技术实现),结合方法调用机制、内存回收保护等使用阶段特性,以及卸载条件和特殊场景处理,帮助开发者深入理解JVM运作原理。同时,文章探讨了性能优化建议、典型异常处理及新一代JVM特性(如元空间与模块化系统)。总结中强调安全优先、延迟加载与动态扩展的设计思想,并提供开发建议与进阶方向,助力解决性能调优、内存泄漏排查及框架设计等问题。
52 5
|
22天前
|
java中一个接口A,以及一个实现它的类B,一个A类型的引用对象作为一个方法的参数,这个参数的类型可以是B的类型吗?
本文探讨了面向对象编程中接口与实现类的关系,以及里氏替换原则(LSP)的应用。通过示例代码展示了如何利用多态性将实现类的对象传递给接口类型的参数,满足LSP的要求。LSP确保子类能无缝替换父类或接口,不改变程序行为。接口定义了行为规范,实现类遵循此规范,从而保证了多态性和代码的可维护性。总结来说,接口与实现类的关系天然符合LSP,体现了多态性的核心思想。
29 0
|
2月前
|
重学Java基础篇—Java Object类常用方法深度解析
Java中,Object类作为所有类的超类,提供了多个核心方法以支持对象的基本行为。其中,`toString()`用于对象的字符串表示,重写时应包含关键信息;`equals()`与`hashCode()`需成对重写,确保对象等价判断的一致性;`getClass()`用于运行时类型识别;`clone()`实现对象复制,需区分浅拷贝与深拷贝;`wait()/notify()`支持线程协作。此外,`finalize()`已过时,建议使用更安全的资源管理方式。合理运用这些方法,并遵循最佳实践,可提升代码质量与健壮性。
64 1
java常见的集合类有哪些
Map接口和Collection接口是所有集合框架的父接口: 1. Collection接口的子接口包括:Set接口和List接口 2. Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及 Properties等 3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等 4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
69 2
哈希表模拟封装unordered_map和unordered_set
哈希表模拟封装unordered_map和unordered_set

热门文章

最新文章