Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

  • Java核心基础

    • 多线程

    • Java常用类

    • 枚举类与注解

    • Java集合

      • Java集合框架概述
      • Collection
      • List
      • ArrayList
      • LinkedList
      • Vector
      • Set
        • 前言
        • 概述
        • 面试题
        • 总结
      • HashSet
      • LinkedHashSet
      • TreeSet
      • Map
      • HashMap
      • LinkedHashMap
      • TreeMap
      • Hashtable
      • Properties
      • Collections工具类
    • 数据结构与算法

    • 泛型

    • IO流

    • 网络编程

    • 反射

    • 函数式编程

  • 设计模式

  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • Java核心基础
  • Java集合
SaulJWu
2020-12-25

Set

# 前言

Java 集合可分为Collection 和Map 两种体系:

  • Collection接口:单列数据,定义了存取一组对象的方法的集合
    • List:元素有序、可重复的集合
      • ArrayList、LinkedList、Vector
    • Set:元素无序、不可重复的集合
      • HashSet、LinkedHashSet、TreeSet
  • Map接口:双列数据,保存具有映射关系“key-value对”的集合,也称为键值对。
    • HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

接下来学习Set接口

# 概述

  • Set接口是Collection的子接口,set接口没有提供额外的方法
  • Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。
  • Set 判断两个对象是否相同不是使用==运算符,而是根据equals() 方法

结论:Set存储无序的、不可重复的数据。

# 面试题

下面输出结果是?

image-20201226213211939

remove p1 后:[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]

重新添加后:[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]

最后:[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
1
2
3
4
5

为什么p1没移除成功?

以下是java.util.HashSet.remove()方法的声明。

public boolean remove(Object o)
1

我们打印一下移除结果,返回false,这是为什么?

**HashSet 集合判断两个元素相等的标准:**两个对象通过hashCode() 方法比较相等,并且两个对象的equals() 方法返回值也相等。

当HashSet使用HashMap实现时,指定元素将保存在Node的key中,而value是HashSet自定义的一个对象,元素的哈希值会保存在节点的hash属性中。

当改变了p1的名字后,HashSet就无法判断这两个元素相等了。所以就remove失败。(虽然遍历还是能指向这个元素,能获取修改后的值)

当已经添加到HashMap中的对象改变了hash值后,不会改变它在HashMap中的位置,此时元素的Hash值和节点的Hash值会不同。

HashSet删除时会根据要删除元素的哈希值,去找到节点相同哈希值的对象,但是我们已经修改了元素的哈希值,所以肯定找不到,所以就返回false,删除失败。

下面准备开始执行remove()方法,看一下HashMap的remove()方法代码:

@Override
public boolean remove(Object key, Object value) {
    return removeNode(hash(key), key, value, true, true) != null;
}
1
2
3
4

调用了removeNode()方法:

final Node<K,V> removeNode(int hash, Object key, Object value,
                           boolean matchValue, boolean movable) {
    Node<K,V>[] tab; Node<K,V> p; int n, index;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (p = tab[index = (n - 1) & hash]) != null) {
        Node<K,V> node = null, e; K k; V v;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            node = p;
        else if ((e = p.next) != null) {
            if (p instanceof TreeNode)
                node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
            else {
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key ||
                         (key != null && key.equals(k)))) {
                        node = e;
                        break;
                    }
                    p = e;
                } while ((e = e.next) != null);
            }
        }
        if (node != null && (!matchValue || (v = node.value) == value ||
                             (value != null && value.equals(v)))) {
            if (node instanceof TreeNode)
                ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
            else if (node == p)
                tab[index] = node.next;
            else
                p.next = node.next;
            ++modCount;
            --size;
            afterNodeRemoval(node);
            return node;
        }
    }
    return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

最快方式去除List内的重复元素

public List removeDuplicateElements(List list){
    HashSet set = new HashSet();
    set.addAll(list);
    return new ArrayList(set);
}
1
2
3
4
5

# 总结

  • Set接口:存储无序的、不可重复的数据
    • HashSet实现类:作为Set接口的主要实现类;线程不安全的;可以存储null值。底层是数组+链表。
      • LinkedHashSet实现类:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。底层是数组+双向链表。
    • TreeSet实现类:可以按照添加对象的指定属性,进行排序。底层是红黑树。
帮我改善此页面 (opens new window)
#Set#HashSet#LinkedHashSet#TreeSet
上次更新: 2020/12/27, 05:12:33
Vector
HashSet

← Vector HashSet→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式