HashSet的存储和遍历

1、特点

1、HashSet实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
2、它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
3、Set接口定一个不包含重复元素的 collection,HashSet的元素自然也不能重复
4、只能存储引用类型,JDK1.5后对基本类型有了自动装箱,会将基本类型自动转换为其包装类。

2、add方法分析

boolean add(E e);如果此 set 中尚未包含指定元素,则添加指定元素。
该方法底层分析:
1、首先获取待添加元素的哈希值(e.hashCode();),与集合中的元素的哈希值进行比较。
2、如果集合中不存在与待添加元素哈希值相同的元素,则将待添加的元素,添加到集合中。(哈希值可以理解为一块内存空间,这块内存里面可能存在多个对象,所以理论上可能出现,多个对象的哈希值相同,地址值不同的情况)
3、如果集合中存在与待添加元素哈希值相同的元素,则调用equals()方法比较这两个元素,如果不相同就添加,否则不添加
注意:如果没有重写equals方法,则调用的是Object中的equal()方法,比较这两个元素的地址,如果地址不相同,就将待添加的元素,添加到集合中,否则不添加。
4、所以一般情况下,需要根据具体的要求重写hashCode方法和equals方法。

3、添加String字符串
Java代码

    public static void main(String[] args) {
        //创建集合对象
        HashSet hs=new HashSet();

        String str1="hello";
        String str2="world";
        String str3="java";
        String str4="hello";

        System.out.println("str1的哈希值:"+str1.hashCode());
        System.out.println("str2的哈希值:"+str2.hashCode());
        System.out.println("str3的哈希值:"+str3.hashCode());
        System.out.println("str4的哈希值:"+str4.hashCode());

        hs.add(str1);
        hs.add(str2);
        hs.add(str3);
        hs.add(str4);
        System.out.println("====================");
        for (String string : hs) {
            System.out.println(string);
        }
    }

运行结果:

str1的哈希值:99162322
str2的哈希值:113318802
str3的哈希值:3254818
str4的哈希值:99162322
====================
world
java
hello

分析:
1、可以看出最后一个hello元素没有进入集合,且集合中的元素顺序和存入的顺序不同。
2、String类重写的hashCode方法,所以获取哈希值,调用的是String类中的hashCode方法
3、上述代码中看到str1和str2、str3的哈希值互不相同,和str4的哈希值相同,
4、集合为空,str1直接添加进入集合,
5、str1、tr2、str3互不相同,所以str2、str3、也添加到集合中,
6、str4与str3的哈希值相同,此时调用String类的equals方法,比较字符串的值,发现相同,不添加str4

4、添加对象

需求:存储自定义对象,并保证元素的唯一性
要求:如果两个对象的成员变量值都相同,则视为同一个元素

学生对象:

package com.xiaowen.demo2;

public class Student {

    private String name;
    private String age;

    public Student() {
    }

    public Student(String name, String age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

}

测试类:

    public static void main(String[] args) {
        //创建集合对象
        HashSet hs=new HashSet();

        //创建学生对象
        Student s1=new Student("小A","10");
        Student s2=new Student("小B","20");
        Student s3=new Student("小C","30");
        Student s4=new Student("小D","40");
        Student s5=new Student("小D","40");

        System.out.println("s4:"+s4.hashCode());
        System.out.println("s5:"+s5.hashCode());

        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);
        hs.add(s4);
        System.out.println("=========================");
        for (Student student : hs) {
            System.out.println(student);
        }   
    }

运行结果:

s4:865113938
s5:1442407170
=========================
Student [name=小D, age=40]
Student [name=小B, age=20]
Student [name=小A, age=10]
Student [name=小C, age=30]
Student [name=小D, age=40]

分析:此时会发现s4和s5的哈希值不同,但是s4和s5的成员变量的值都相同,所以集合中出现了重复的元素(此处的重复指的是成员变量值都相同),此时调用的是Object中的hashCode和equals方法,所以就需要在Student类中重写hashCode方法和equals方法。

重写后的Student类:

package com.xiaowen.demo2;

public class Student {

    private String name;
    private String age;

    public Student() {
    }

    public Student(String name, String age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    //根据成员变量的哈希值和成员变量的值,按照如下规则生成新的哈希值
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        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;
        Student other = (Student) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }   
}

运行结果:此时 s5没有添加到集合中

s4:783066
s5:783066
=========================
Student [name=小D, age=40]
Student [name=小C, age=30]
Student [name=小B, age=20]
Student [name=小A, age=10]

分析:
1、重写hashCode方法,根据成员变量的哈希值和成员变量的值,按照一定的规则生成新的哈希值
2、重写equals方法,比较成员变量的值

补充:
LinkedHashSet:底层数据结构由哈希表和链表组成,其特点是元素唯一且有序

你可能感兴趣的:(Java基础知识)