Java学习(set接口、HashSet集合)

一、set接口

概念:set接口继承自Collection接口,与List接口不同的是,set接口所储存的元素是不重复的。

二、HashSet集合

概念:是set接口的实现类,由哈希表支持(实际上是一个HashMap集合)。HashSet集合元素的提取顺序与存储顺序不相同

   采用哈希表数据结构存储数据,保证元素唯一性的方式依赖于:hashCode()与equals()方法

2.1哈希表

  什么是哈希表? 链表与数组的组合

  哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时

那么会根据这些对象的特有数据结合相应的算法计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组即就是哈希表

  当向哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是Object类中的hashCode方法。由于任何对象都是Object类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的hashCode方法算出对象在表中的存放位置,这里需要注意,如果两个对象hashCode方法算出结果一样,这样现象称为哈希冲突,这时会调用对象的equals方法比较这两个对象是不是同一个对象,如果equals方法返回的是true,那么就不会把第二个对象存放在哈希表中,如果返回的是false就会把这个值存放在哈希表中。

  总结:保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

  Hashcode方法用来计算哈希值。

hashCode方法计算图:

哈希表数组和链表的结合图

2.2HashSet存储JavaAPI中的类型元素

给HashSet中存储JavaAPI中提供的类型元素时,不需要重写元素的hashCode和equals方法因为这两个方法,在JavaAPI的每个类中已经重写完毕,如String类、Integer类等。

练习实例:

1.向哈希表添加元素并且打印

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;

public class Demo01 {
    //哈希表
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        method1();
     method2();
     method3();
     method4();
}
public static void method1(){ HashSet<String> set=new HashSet<String> (); set.add("abc"); set.add("abc"); set.add("ghi"); System.out.println(set); // }

打印结果:因为唯一性,所以只存储了一个“abc”.

2.打印哈希值

//hashcode 方法(object类中提供)
    public static void method2(){
        String s1=new String("abc");
        String s2=new String("abc");
        //运行出来的 叫哈希值    运行的hashcode是string类的
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
    }

打印结果:哈希值  hashCode()

3.向哈希表中添加自定义类的元素并打印

自定义Person类:

public class Person {
    private String name;
    private int age;
    public Person(){
        
    }
    //重载构造方法,创建时赋值
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    
    @Override
    //转为字符串
    public String toString() {
        return "Person [name=" + name + ", 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
    //重写hashCode()方法
    public int hashCode() {
        
        return name.hashCode()+age*31;
    }
    @Override
    //重写equals()方法
    public boolean equals(Object obj) {
        if(this==obj){
            return true;
        }
        if(obj==null){
            return false;
        }
        if(obj instanceof Person){
            Person p=(Person) obj;
            return name.equals(p.name)&&age==p.age;
        }
        return false;
    }
}

测试类方法:

public static void method3(){
        HashSet<Person> set=new HashSet<Person>();
        set.add(new Person("a",20));
        set.add(new Person("a",10));
        set.add(new Person("b",30));
        set.add(new Person("b",30));
        System.out.println(set);
    }

运行结果:因为重写了hashCode方法跟equals方法  所以重复的元素并没有存储到集合中

三、LinkedHashSet集合:

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?

在HashSet下面有一个子类LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

实例:迭代器遍历有序唯一输出:

//迭代器遍历有序唯一输出
    public static void method4(){
        LinkedHashSet<String> set=new LinkedHashSet <String>();
        set.add("a");
        set.add("aabbb");
        set.add("张三");
        set.add("李四");
        set.add("a");
        set.add("李四");
        Iterator it=set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }        
    

 运行结果:按照存储顺序打印

四、 判断集合元素唯一的原理

 4.1ArrayListcontains方法判断元素是否重复原理

 

ArrayList的contains方法会使用调用方法时,传入的元素的equals方法依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素

true则有,false则无)。此时,ArrayList存放自定义类型时,由于自定义类型在未重写equals方法前,判断是否重复的依据是地址值,

所以如果想根据内容判断是否为重复元素,需要重写元素的equals方法

4.2HashSetadd/contains等方法判断元素是否重复原理

Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。

HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:

先判断新元素与集合内已经有的旧元素的HashCode值

如果不同,说明是不同元素,添加到集合。

如果相同,再判断equals比较结果。返回true则相同元素;返回false则不同元素,添加到集合。

所以,使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,则判断重复时,使用的是地址值,如果想通过内容比较元素是否相同,

需要重写该元素类的hashcode与equals方法

猜你喜欢

转载自www.cnblogs.com/0328dongbin/p/9122660.html