zoukankan      html  css  js  c++  java
  • java集合之HashSet

    HashSet:位于java.util包下


    1 HashSet概述

    特点:作为Set集合的一种,首先是无序的,不可重复的;允许存放null值;底层封装HashMap;实现是不同步的,线程不安全;

    常用构造:

      public HashSet() :构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。

    常用方法:

    1)添加功能

    boolean  add(E e)  : 如果此 set 中尚未包含指定元素,则添加指定元素

    2)判断功能

    boolean  isEmpty(): 如果此 set 不包含任何元素,则返回 true

    boolean contains(Object o): 如果此列表中包含指定的元素,则返回 true

    3)获取功能

    int size() : 返回此 set 中的元素的数量(set 的容量)。

    4)删除功能

    void clear() :移除此列表中的所有元素。注意:此方法比较暴力,一般不使用。

    boolean remove(Object o):如果指定元素存在于此 set 中,则将其移除。

    5)迭代器功能

    public Iterator<E> iterator() 返回对此 set 中元素进行迭代的迭代器。返回元素的顺序并不是特定的。


    2 HashSet的使用

    1)使用HashSet存储字符串如何实现存储元素的唯一性??

    package SetTest;

    import java.util.HashSet;
    import java.util.Set;

    public class HashSetDemo1 {
      public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        set.add("java");
        set.add("js");
        set.add("sql");
        set.add("java");
        set.add("js");
        set.add("jquery");

        for(String s:set){
          System.out.println(s);
        }
      }
    }

    输出结果:

    java
    js
    jquery
    sql

    分析:

    1)通过查看add()方法的源码,底层是使用HashMap的put()方法实现元素的存取,继续查看put存储元素的源码,可知要保证存储元素的唯一性依赖于元素的equals和hashCode方法的实现,首先看hashCode方法,如果存在hash值和待存储元素的hash值相等的元素,则继续通过equals方法比较二者。如果相等则不存储。

    2)由于String类重写了equals()和hashCode()方法: 这两个方法都是依赖于String对象的内容》》只有字符串内容一样就认为是相等的,不会在集合中存储。

    public int hashCode() {
      int h = hash;
      if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
          h = 31 * h + val[i];   //hash值的生成依赖于字符串的内容
        }
        hash = h;
      }
      return h;
    }

    public boolean equals(Object anObject) {
      if (this == anObject) {
        return true;
      }
      if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
          char v1[] = value;
          char v2[] = anotherString.value;
          int i = 0;
          while (n-- != 0) {    //判断两个字符串是否相等,依赖于字符串的内容是否一样
            if (v1[i] != v2[i])
              return false;
            i++;
          }
          return true;
        }
      }
      return false;
    }

    同样在存储其他基本类型的装箱类型也可以实现存储元素的唯一性,因为这些装箱类型也实现了equals()和hashCode()方法。(如Integer,Character等)

    2)使用HashSet存储自定义对象:如何保证存储元素的唯一性(此处我们认为Student的name和age相等就意味着元素相等)

    package SetTest;

    public class Student {
      private String name;
      private int age;
      public Student(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 "Student [name=" + name + ", age=" + age + "]";
      }

      @Override
      public int hashCode() {
        int hash = name.hashCode()+age;
        return hash;
      }
      @Override
      public boolean equals(Object obj) {
        if(this==obj)
          return true;
        if(obj instanceof Student){
          Student stu = (Student)obj;
          if(stu.getName().equals(name) && stu.getAge()==age)
            return true;
        }
        return false;
      }
    }

    package SetTest;

    import java.util.HashSet;
    import java.util.Set;

    public class HashSetTest {
      public static void main(String[] args) {
        Set<Student> set = new HashSet<Student>();

        Student stu1 = new Student("hu",12);
        Student stu2 = new Student("wen",27);
        Student stu3 = new Student("rt",12);
        Student stu4 = new Student("you",15);
        Student stu5 = new Student("hu",12);
        Student stu6 = new Student("te",17);
        Student stu7 = new Student("wen",27);

        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        set.add(stu5);
        set.add(stu6);
        set.add(stu7);

        for(Student s:set){
          System.out.println(s.getName()+"------"+s.getAge());
        }
      }
    }

    输出结果:

    te------17
    hu------12
    wen------27
    rt------12
    you------15

     分析:

    从输出结果可知,此集合的存储保证了元素的唯一性,主要是因为我们在自定义类中重写了equals和hashCode方法。

     总结:

    要想在hashSet集合中实现元素存取的唯一性,由于底层判断依赖于equals和hashCode方法,故所存取的元素需要重写这两个方法,以按照我们的期待存取元素。保证元素唯一性。

    重新强调下

    hashCode和equals方法的使用概念非常重要:不仅可以用于set还可以用于map。
    1)使用java系统类,如String/Date/或者数字包装类(Integer/Float),不必重写hashCode和equals方法。
    2)如果要在set或者map中添加自定义类的实例,就要确保equals和hashCode方法能正常工作,否则代码可能出现无法预料的结果


     HashSet和其子类LinkedHashSet的区别:

    简单的例子:

    HashSet<Student> set1 = new HashSet<Student>();
    Student stu1 = new Student("wen",12);
    Student stu2 = new Student("di",15);
    Student stu3 = new Student("wu",13);
    Student stu4 = new Student("yy",14);
    Student stu5 = new Student("fr",16);
    Student stu6 = new Student("vc",11);
    Student stu7 = new Student("aw",10);

    set1.add(stu1);
    set1.add(stu2);
    set1.add(stu3);
    set1.add(stu4);
    set1.add(stu5);
    set1.add(stu6);
    set1.add(stu7);
    System.out.println("-----------------HashSet----------------------");
    for(Student stu:set1){
      System.out.println(stu.getName()+"-----------"+stu.getAge());
    }

    System.out.println("-----------------LinkedHashSet----------------------");
    LinkedHashSet<Student> set2 = new LinkedHashSet<Student>();
    set2.add(stu1);
    set2.add(stu2);
    set2.add(stu3);
    set2.add(stu4);
    set2.add(stu5);
    set2.add(stu6);
    set2.add(stu7);
    for(Student stu:set2){
      System.out.println(stu.getName()+"-----------"+stu.getAge());
    }

    输出结果是:

    -----------------HashSet----------------------
    wu-----------13
    yy-----------14
    vc-----------11
    wen-----------12
    di-----------15
    fr-----------16
    aw-----------10
    -----------------LinkedHashSet----------------------
    wen-----------12
    di-----------15
    wu-----------13
    yy-----------14
    fr-----------16
    vc-----------11
    aw-----------10

    LinkedHashSet的功能与HashSet类似,毕竟是其子类。

    有一个重要的区别:LinkedHashSet返回的元素顺序是可以预测的,即元素添加到集合的顺序。
    该功能可以用来快速查找并判断集合中是否包含指定对象,或者用于检索元素并按照元素的添加顺序返回元素。


  • 相关阅读:
    moment.js相关知识总结
    git相关使用解释
    .我的第一篇博客
    QT项目配置
    重载->
    内核对象同步
    模式对话框与非模式对话框
    显示与隐式类型转换
    size_t与size_type
    系统级源代码:系统裁剪
  • 原文地址:https://www.cnblogs.com/zwbg/p/5906542.html
Copyright © 2011-2022 走看看