集合框架之 Set 集合——特定归纳总结

简介: 集合框架之 Set 集合——特定归纳总结

一、set集合

1.1 set集合的特点

  1. 加入集合的顺序与取出集合的顺序不一定
  2. 没有索引
  3. 存储元素不能重复

1.2  哈希值

       哈希值:是JDK根据u第项的地址或者数字运算出来的int类的数值;

       Object类中有一个方式可以获取哈希值, public int hashCode();返回哈希值。

  对象哈希值的特点 :

  1. 同一个对象多次调用和hashCode()方法返回的哈希值是相同的。
  2. 默认情况下,不同对象的哈希值是不同,但可以通过重写hashCode方法使得哈希值相同。    

1.3. set集合应用场景

  1. 去重。因为Set集合中的元素不允许重复,所以可以用来去除列表或其他数据结构中的重复元素。
  2. 数学操作。由于Set集合支持并集、交集、差集等数学运算,所以它常用于对数据进行数学处理。
  3. 缓存。Set集合的查询速度非常快,这使得它成为一个很好的缓存工具。我们可以把需要频繁查询的数据存储在Set集合中,随时使用。
  4. 查找元素。Set集合提供了基于哈希表的查找功能,它可以快速地判断一个元素是否存在于集合中。
  5. 过滤器。Set集合可以作为过滤器使用,我们可以将一些不需要的元素存储在Set集合中,然后通过过滤器将这些元素从数据中过滤掉。

❕❕❕平常工作中,在调用第三方工具接口时可能会返回重复数据,这时可用到set集合存储进行去重

二、遍历方式

       2.1foreach

       2.2iterator (迭代器)

package com.ycxw.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
 * set集合的两种遍历方式 
 * 1.foreach 
 * 2.iterator
 * 
 * @author 云村小威
 *
 */
public class Text_01 {
  public static void main(String[] args) {
    Set hs = new HashSet<>();
    // 添加元素
    hs.add(new String("小黑子"));
    hs.add("ikun");
    hs.add(new String("小母鸡"));
    hs.add("绿湿涵");
    // foreach遍历输出
    for (Object object : hs) {
      System.out.println(object);
    }
    // iterator遍历
    Iterator i = hs.iterator();
    while (i.hasNext()) {
      System.out.println(i.next());
    }
  }
}

三、HashSet存储去重原理

3.1 HashSet集合的特点

  1. 底层数据结构是哈希表
  2. 对集合的比迭代是无序的,也就是说不保证存储和取出的先后顺序一致;
  3. 没有带索引的方法,所以不能用普通的for循环遍历, 但可以用加强for和 iterator 迭代器遍历
  4. 由于是Set集合,所以不会存储重复元素

3.2 HashSet唯一性原理

      新添加到HashSet集合的元素都会行比较,首先会调用HashCode方法比较元素的哈希值,如果哈希值不同则将元素添加到集合(qeuals方法不会调用)

如果哈希值相同,则还会调用equals方法进行比较,如果返回flase(说明新添的元素与已有的元素的属性值不相同) 就添加到集合

如果调用equals方法进行比较如果,返回true(说明新添的元素与已有的元素的属性值相同) 则不会添加到集合

如图所示,添加了重复元素及对象,输出时是去重的且无序。

注意:如果存储的是实体对象则必须重写hashCode和equals方法,不然不会去重。

package com.ycxw.set;
import java.util.HashSet;
import java.util.Set;
/**
 * 
 * @author 云村小威
 *
 */
public class Text_02 {
  public static void main(String[] args) {
    Set hs = new HashSet<>();
    // 添加元素
    hs.add(new Person("ikun", 18));
    hs.add(new Person("珍爱粉", 20));
    hs.add(new Person("ikun", 18));
    // foreach遍历输出
    for (Object object : hs) {
      System.out.println(object);
    }
  }
}
class Person {
  private String name;
  private int 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;
  }
  public Person(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  }
//  @Override
//  public int hashCode() {
//    final int prime = 31;
//    int result = 1;
//    result = prime * result + age;
//    result = prime * result + ((name == null) ? 0 : name.hashCode());
//    return result;
//  }
//
//  @Override
//  public boolean equals(Object obj) {
//    if (this == obj)
//      return true;
//    if (obj == null)
//      return false;
//    if (getClass() != obj.getClass())
//      return false;
//    Person other = (Person) obj;
//    if (age != other.age)
//      return false;
//    if (name == null) {
//      if (other.name != null)
//        return false;
//    } else if (!name.equals(other.name))
//      return false;
//    return true;
//  }
  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
  }
}

如上操作我把重写的hashCode和equals方法注释,所以能存储重复的对象。

四、TreeSet(自然排序,比较器排序)

4.1 TreeSet 集合特点

  1. 元素有序:这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方法取决于构造方法。  
  2. 实现Compareator接口根据其元素的自然排序进行排序;
  3. TreeSet (Comparator comparator) 根据指定的比较器进行排序
  4. 没有索引的方法:所以不能用普通的for循环遍历,可以用加强for或迭代器iterator
  5. 由于是Set集合,所以不包含重复元素

4.2 自然排序Comparable的使用

package com.ycxw.set;
import java.util.TreeSet;
/**
 * TreeSet自然排序Comparable的使用
 * @author 云村小威
 *
 */
public class Text_02 {
  public static void main(String[] args) {
    TreeSet ts = new TreeSet<>();
    // 添加元素
    ts.add(new Person(1, "ikun", 18, 10000));
    ts.add(new Person(2, "珍爱粉", 20, 100000));
    ts.add(new Person(4, "陆诗涵", 21, 6000));
    ts.add(new Person(3, "纯路人", 18, 3000));
    // foreach遍历输出
    for (Object object : ts) {
      System.out.println(object);
    }
  }
}
// 创建一个实体实现Comparable接口
class Person implements Comparable<Person> {
  private int id; // 编号
  private String name; // 名称
  private int age; // 年龄
  private int yue; // 余额
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  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;
  }
  public int getYue() {
    return yue;
  }
  public void setYue(int yue) {
    this.yue = yue;
  }
  public Person(int id, String name, int age, int yue) {
    super();
    this.id = id;
    this.name = name;
    this.age = age;
    this.yue = yue;
  }
    @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + id;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + yue;
    return result;
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    User other = (User) obj;
    if (age != other.age)
      return false;
    if (id != other.id)
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    if (yue != other.yue)
      return false;
    return true;
  }
  @Override
  public String toString() {
    return "Person [id=" + id + ", name=" + name + ", age=" + age + ", yue=" + yue + "]";
  }
  @Override
  public int compareTo(Person o) {
    // this.id 是被比较的对象及属性 (升序)
    // return o.id - this.id (降序)
    return this.id - o.id;
  }
}

这时默认根据编号排序,那如何修改呢?

@Override

   public int compareTo(Person o) {

       // this.id 是被比较的对象及属性 (升序)

       // return o.id - this.id (降序)

       return this.id - o.id;

   }

只需修改返回别比较的属性的即可。

这里注意如不实现Comparable接口则会报这个错误

Exception in thread "main" java.lang.ClassCastException: com.ycxw.set.Person cannot be cast to java.lang.Comparable

4.3 比较器排序Comparator 的使用

package com.ycxw.set;
import java.util.Comparator;
import java.util.TreeSet;
/**
 * TreeSet比较器排序Comparable的使用
 * 
 * @author 云村小威
 *
 */
public class Text_03 {
  public static void main(String[] args) {
    TreeSet ts = new TreeSet<>(new Comparator<User>() {
      @Override
      public int compare(User o1, User o2) {
        // 根据年龄进行降序排序
        return o2.getAge() - o1.getAge();
      }
    });
    // 添加元素
    ts.add(new User(1, "ikun", 18, 10000));
    ts.add(new User(2, "珍爱粉", 20, 100000));
    ts.add(new User(4, "陆诗涵", 21, 6000));
    ts.add(new User(3, "纯路人", 19, 3000));
    // foreach遍历输出
    for (Object object : ts) {
      System.out.println(object);
    }
  }
}
// 创建一个实体实现Comparable接口
class User implements Comparable<User> {
  private int id; // 编号
  private String name; // 名称
  private int age; // 年龄
  private int yue; // 余额
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  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;
  }
  public int getYue() {
    return yue;
  }
  public void setYue(int yue) {
    this.yue = yue;
  }
  public User(int id, String name, int age, int yue) {
    super();
    this.id = id;
    this.name = name;
    this.age = age;
    this.yue = yue;
  }
    @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + id;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + yue;
    return result;
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    User other = (User) obj;
    if (age != other.age)
      return false;
    if (id != other.id)
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    if (yue != other.yue)
      return false;
    return true;
  }
  @Override
  public String toString() {
    return "Person [id=" + id + ", name=" + name + ", age=" + age + ", yue=" + yue + "]";
  }
  @Override
  public int compareTo(User o) {
    // TODO Auto-generated method stub
    return 0;
  }
}

如我的需求事先比较年龄再比较余额呢?

@Override

           public int compare(User o1, User o2) {

               int num = o2.getAge() - o1.getAge(); //上一个对象 - 当前对象 降序

               //判断num如果等于0就代表年龄是一样的

               if(num==0) {

                   //则按余额进行降序

                   return o2.getYue() - o1.getYue();

               }

               // 根据年龄进行降序排序

               return num;

           }

       });

根据自身需求修改此处即可;

总之,Set集合是一种非常常用的数据结构,它可以快速地进行查找、插入和删除操作,并且支持数学中的集合运算,被广泛应用于各种计算机程序的实现中。

相关文章
|
19天前
|
存储 NoSQL 关系型数据库
Redis 集合(Set)
10月更文挑战第17天
31 5
|
20天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
34 6
|
20天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
31 2
|
4天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
4天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
4天前
|
Java 开发者
|
20天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
【10月更文挑战第16天】Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。通过 hashCode() 和 equals() 方法实现唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 添加和遍历元素,体现了 Set 的高效性和简洁性。
23 4
|
22天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。它通过 hashCode() 和 equals() 方法确保元素唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 实现这一特性。
23 5
|
20天前
|
Java 开发者
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素。通过哈希表和红黑树两种模式,Set能够高效地识别并拒绝重复元素的入侵,确保集合的纯净。无论是HashSet还是TreeSet,都能在不同的场景下发挥出色的表现,成为开发者手中的利器。
24 2
|
29天前
|
存储 JavaScript 前端开发
Set、Map、WeakSet 和 WeakMap 的区别
在 JavaScript 中,Set 和 Map 用于存储唯一值和键值对,支持多种操作方法,如添加、删除和检查元素。WeakSet 和 WeakMap 则存储弱引用的对象,有助于防止内存泄漏,适合特定场景使用。