Java——集合中的Set接口通过HashSet类实现一些常用的方法

简介: Java——集合中的Set接口通过HashSet类实现一些常用的方法

任何复杂的知识往往给人的感觉都是那么的不友好,所以,一定要静下心来,耐心去看、去读、去理解这些东西!!!  


1.Set接口的简介


说明:Set 接口和 List 接口一样,同样继承自 Collection 接口。 

特点:Set 接口中的元素无序,并且都会以某种规则保证存入的元素不出现重复。


2.HashSet类简介


说明:HashSet Set 接口的一个实现类,它所存储的元素不可重复,并且无序。

特点:当向 HashSet 集合中添加一个元素时,首先会调用该元素的 hashCode() 方法来确定元素的存储位置,然后再调用元素对象的equals() 方法来确保该位置没有重复元素。

 

3.HashSet类的常用方法


import java.util.*;
/*import java.util.HashSet;
  import java.util.Iterator;*/
public class HashSetDemo {
  public static void main(String[] args) {
    HashSet<String> hash=new HashSet<String>();
    System.out.println("↓↓↓HashSet集合常用方法如下↓↓↓");
    System.out.println("---------------------------------------------");
    System.out.println("创建第一个空的HashSet集合,元素类型为String类:" + hash);
    System.out.println("hash集合此时为空:" + hash.isEmpty());
    System.out.println("---------------------------------------------");
    hash.add("A");
    hash.add("B");
    hash.add("C");
    hash.add("D");
    hash.add("A");//元素无序,不能重复
    System.out.println("向hash集合中添加指定元素:" + hash);
    System.out.println("此时hash集合的长度为:" + hash.size());
    System.out.println("---------------------------------------------");
    System.out.print("使用迭代器遍历hash集合:");
    //第一步:使用集合中的iterator()方法,获取送代器的实现类对象
                //第二步:使用Iterator接口接收(多态)
    Iterator iterator=hash.iterator();
    while(iterator.hasNext()) {
      /*第三步:使用Iterator接口中的hasNext()方法来判断集合中还有没有下一个元素
        如果有下一个元素,那么就调用Iterator接口的next()方法,取出下一个元素,并且会把指针向后移一位
        第四步:使用Iterator接口中的next()方法来取出集合中的下一个元素
        以此类推,直到hasNext()方法返回false,表示到达了集合的末尾终止对元素的遍历*/
      System.out.print(iterator.next() + " ");
    }
    System.out.println();
    System.out.println("---------------------------------------------");
    System.out.println("使用for-each循环遍历hash集合,同时获取每个元素和哈希值:");
    for(String a : hash) {
      System.out.print(a + " " + a.hashCode() + ",");
    }
    System.out.println();
    System.out.println("---------------------------------------------");
    System.out.println("hash集合中是否包含元素\"A\":" + hash.contains("A"));
    System.out.println("---------------------------------------------");
    hash.remove("D");
    System.out.println("移除元素\"D\"之后的hash集合为:" + hash);
    System.out.println("---------------------------------------------");
    hash.clear();
    System.out.println("清空hash集合中的所有元素:" + hash);
    System.out.println("---------------------------------------------");
  }
}


4.Java程序中的哈希值


Java 中的哈希值:是一个十进制的整数,由系统随机给出的二进制数经过换算得到的。其实它就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,并不是数据实际存储的物理地址。

Object类有一个方法,可以获取对象的哈希值:int hashCode() 返回对象的哈希码值。
hashCode()
方法源码:public native int hashCode()  native:代表该方法是调用本地操作系统的方法。

下面,我们举个例子来看一下:👇👇👇

class Person extends Object {
//Java中的所有类都默认继承了Object类,这里不写extends Object也可以
  private String name;
  private int age;
  public Person() { 
  }
  public Person(String name,int age) {
    this.name=name;
    this.age=age;
  }
  public String getName() {
    return this.name;
  }
  public int getAge() {
    return this.age;
  }
}
public class HashCode {
  public static void main(String[] args) {
    Person p1=new Person("张三",20);//通过构造方法创建两个类对象
    Person p2=new Person("李四",22);
    int x1=p1.hashCode();//调用Object类的hashCode方法,获取哈希值,p1的哈希值是不变的
    System.out.println("对象p1的哈希值为:" + x1);
    int x2=p2.hashCode();//调用Object的hashCode方法,获取哈希值,p2的哈希值也是不变的
    System.out.println("对象p2的哈希值为:" + x2);
  }
}


4.1 假如覆盖重写hashCode方法,所创建的对象的哈希值就会被影响


class Person extends Object {
//Java中的所有类都默认继承了Object类,这里不写extends Object也可以
  public int hashCode() {
    return 999;
  }
}
public class HashCode {
  public static void main(String[] args) {
    Person p1=new Person();//通过构造方法创建两个类对象
    Person p2=new Person();
    int x1=p1.hashCode();//调用Object类的hashCode方法,获取哈希值,p1的哈希值是不变的
    System.out.println("对象p1的哈希值为:" + x1);
    int x2=p2.hashCode();//调用Object的hashCode方法,获取哈希值,p2的哈希值也是不变的
    System.out.println("对象p2的哈希值为:" + x2);
  }
}
//此时对象p1和p2的哈希值为:999

 

5.Set集合存储元素不重复的原理


5.1 概念理解


set 集合在调用 add() 方法的时候,add()方法会调用元素的 hashCode() 方法和equals() 方法判断元素是否重复。


5.2 应用举例


import java.util.*;
public class HashCode {
  public static void main(String[] args) {
    HashSet<String> hashset=new HashSet<String>();
    String s1=new String("abc");
    String s2=new String("abc");
    hashset.add(s1);
    hashset.add(s2);
    hashset.add("LOL");
    hashset.add("DNF");
    System.out.println("s1的哈希值:" + s1.hashCode());
                System.out.println("s2的哈希值:" + s2.hashCode());
                System.out.println("LOL的哈希值:" + "LOL".hashCode());
                System.out.println("DNF的哈希值:" + "DNF".hashCode());
                System.out.println("HashSet集合:" + hashset);
  }
}

5.3 代码讲解


最初,hashset集合是空的

hashset.add(s1)的时候,

第一步:add()方法首先会调用 s1hashCode()方法,计算字符串"abc"的哈希值,其哈希值是 96354

第二步:查找集合中哈希值是 96354中的元素,没有发现哈希值是96354key

第三步:将s1存储到集合hashset中(于是集合hashset中存在哈希值96354,且对应这数据 s1


hashset.add(s2)的时候

第一步:add()方法首先会调用 s2hashCode()方法,计算字符串"abc"的哈希值,其哈希值是96354

第二步:查找集合hashset中是否存在哈希值是 96354,即哈希值96354冲突,

第三步:s2调用 equals()方法,和集合中哈希值是 96354对应的元素进行比较

第四步:s2.equals(s1)返回 true,即哈希值是96354对应的元素已经存在,所以就不添加 s2进集合了(其中:s1 = "abc"s2 = "abc")


hashset.add("LOL")的时候

第一步:调用 "LOL" hashCode()方法,计算字符串 "LOL" 的哈希值,其哈希值是640503

第二步:查找集合中哈希值是 640503中的元素,没有发现哈希值是 640503key

第三步:将 "LOL" 存储到集合hashset中(于是集合hashSet中存在哈希值640503,且对应这数据 "LOL"


hashset.add("DNF")的时候

第一步:调用 "DNF" hashCode()方法,计算字符串 "DNF" 的哈希值,其哈希值是644843

第二步:查找集合中哈希值是 644843中的元素,没有发现哈希值是644843key

第三步:将 "DNF" 存储到集合hashSet中(于是集合hashset中存在哈希值644843,且对应这数据"DNF"

添加完成,集合hashset = [abc, LOL, DNF]

 

6.HashSet存储自定义类型元素


HashSet 存储自定义类型元素,那么自定义的类必须重写hashCode() 方法和 equals() 方法,否则添加的元素可以出现重复,我们平时使用的类型,它们都重写Object 类的 hashCode() 方法和 equals() 方法。


6.1 假如不重写Object类的hashCode()方法和equals()方法


import java.util.*;
class Person extends Object {
//Java中的所有类都默认继承了Object类,这里不写extends Object也可以
  private String name;
  private int age;
  public Person() { 
  }
  public Person(String name,int age) {
    this.name=name;
    this.age=age;
  }
  public String getName() {
    return this.name;
  }
  public int getAge() {
    return this.age;
  }
  public String toString() {
    return "Person{" + "name=\"" + name + "\"" + ",age=" + age + "}";
  }
}
public class HashCode {
  public static void main(String[] args) {
    HashSet<Person> hashset=new HashSet<Person>();
    Person p1=new Person("小明",20);
    Person p2=new Person("小明",20);
    Person p3=new Person("小红",25);
    hashset.add(p1);
    hashset.add(p2);
    hashset.add(p3);
    System.out.println("创建的hashset集合为:" + hashset);
  }
}

可以看到,hashset 集合里面可以存在重复的元素。


6.2 重写Object类的hashCode()方法和equals()方法

import java.util.*;
class Person extends Object {
//Java中的所有类都默认继承了Object类,这里不写extends Object也可以
  private String name;
  private int age;
  public Person() { 
  }
  public Person(String name,int age) {
    this.name=name;
    this.age=age;
  }
  public String getName() {
    return this.name;
  }
  public int getAge() {
    return this.age;
  }
  public String toString() {
    return "Person{" + "name=\"" + name + "\"" + ",age=" + age + "}";
  }
  public boolean equals(Object o) {
        if(this==o) {//参数==对象
            return true;
        }
        if(o==null || getClass()!=o.getClass()) {//传入参数为空,或者对象与参数的hashCode不相等
            return false;
        }
        Person person=(Person) o;//向下转型,把Object类型转型为Person类型
        return age==person.age && Objects.equals(name,person.name);//返回 age,name
    }
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class HashCode {
  public static void main(String[] args) {
    HashSet<Person> hashset=new HashSet<Person>();
    Person p1=new Person("小明",20);
    Person p2=new Person("小明",20);
    Person p3=new Person("小红",25);
    hashset.add(p1);
    hashset.add(p2);
    hashset.add(p3);
    System.out.println("创建的hashset集合为:" + hashset);
  }
}


可以看到,输出结果中,hashset 集合的元素并没有重复,因此,如果我们想要用Hashset集合存储自定义类型的数据,一定要记得覆盖重写 hashCode() 方法和 equals() 方法。

相关文章
|
5天前
|
SQL Java API
使用Java Stream API简化集合操作
使用Java Stream API简化集合操作
|
3天前
|
存储 Java 索引
Java基础之集合
“【7月更文挑战第7天】”Java集合框架用于存放对象,包括List(如ArrayList、LinkedList、Vector)、Set(如HashSet、LinkedHashSet、TreeSet)和Queue(如PriorityQueue、ArrayDeque)。集合存放对象引用,基本类型自动转换为包装类。Collection是最基础接口,其子接口List、Set和Queue定义不同集合行为。Java提供抽象类和实现类简化开发,例如AbstractList、ArrayList、LinkedList等。集合通过Iterator遍历,也可用增强for循环。
33 11
|
3天前
|
存储 安全 Java
Java基础之集合Map
【7月更文挑战第8天】Java中的Map集合以键值对方式存储数据,如`Map&lt;&quot;name&quot;, &quot;张三&quot;&gt;`。Map接口定义了存取、判断、移除等操作,包括`put`、`get`、`containsKey`等方法。HashMap是最常用的实现,基于哈希表,允许null键值,但不保证顺序。其他实现包括同步的Hashtable、处理属性文件的Properties、保持插入顺序的LinkedHashMap、基于红黑树的TreeMap、弱引用的WeakHashMap、并发安全的ConcurrentHashMap和针对枚举优化的EnumMap。
11 4
|
2天前
|
安全 算法 Java
Java面试题:如何使用并发集合,例如ConcurrentHashMap?
Java面试题:如何使用并发集合,例如ConcurrentHashMap?
12 1
|
2天前
|
设计模式 缓存 安全
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
9 1
|
5天前
|
Java API
如何利用Java Stream API简化集合操作?
如何利用Java Stream API简化集合操作?
|
2天前
|
存储 安全 Java
Java面试题:请解释Java中的泛型集合框架?以及泛型的经典应用案例
Java面试题:请解释Java中的泛型集合框架?以及泛型的经典应用案例
8 0
|
2天前
|
安全 Java 开发者
Java多线程:Java中如何创建线程安全的集合,编程中如何优化Java多线程集合
Java多线程:Java中如何创建线程安全的集合,编程中如何优化Java多线程集合
14 0
|
4天前
|
存储 安全 Java
Java Map集合:选择正确的实现方式
Java Map集合:选择正确的实现方式
|
4天前
|
Java API
如何利用Java Stream API简化集合操作?
如何利用Java Stream API简化集合操作?