Java集合学习总结-------Set接口

Set接口

Set集合Java集合框架中的非常重要的组成部分。Set集合不能存重复的元素。这里的重复是根据该对象所属的类的equals方法和hashCode方法来判断的

只有当两个对象的hashcode相同,且equals方法返回true时,才断定两个对象相等。

代码验证:

import java.util.Objects;

/**
 * @auther plg
 * @date 2019/4/8 21:08
 */
public class Person {
    private static int num = 0;
    private String name;
    private Integer age;
    public Person(){}
    public Person(String name,Integer age){
        this.age = age;
        this.name = name;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(name, person.name) &&
                Objects.equals(age, person.age);
    }

    @Override
    public int hashCode() {
        return num++;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

这样覆写的hashCode方法,每个对象的hashcode都是在它的前一个对象的基础上加一,因此这样创建的多个对象的hashcode是不会相等的。

测试代码:

public static void testHashSet(){
    HashSet<Person> set = new HashSet<>();
    set.add(new Person("Javk",18));
    set.add(new Person("Javk",18));
    set.add(new Person("Javk",18));
    System.out.println(set);
}

运行结果:
在这里插入图片描述
可以看到三个元素都存进了Set集合中。

这便是因为虽然这三个对象的值相等,即调用equals方法返回的结果是true,但hashcode不相同,因此认为它们三个是不同的对象,所有可以存进HashSet中。

覆写equals和hashCode方法的要求

1.equals方法判断相等,则hashCode必须相等。

2.equals方法判断不相等,hashCode尽量不相等(否则造成hash碰撞,但确实存在相等的情况,这是由散列函数的性质而产生的)。

3.同一个对象调用多次hashCode方法都应产生同样的结果。

经典面试题1:覆写equals方法为什么一定要覆写hashCode方法

首先说一下为什么要覆写equals方法?equals方法和hashCode方法都是Object类的方法,而equals方法默认的比较的是两个对象的地址是否相等。

方法源码:

public boolean equals(Object obj) {
    return (this == obj);
}

但在实际开发中,通常对对象的地址是不太关心的,而更关心的是对象的内容。因此这才有必要覆写equals方法。

如果只重写equals方法而没有覆写hashCode方法,则默认使用的是Object类中的hashCode方法,该方法是一个本地方法,是根据对象的地址来算hash值的。两个new的对象即使它们的内容相同,它们的地址也必然是不同的。

这便违反了上述的第一条规则:equals相同,hashCode也必须相同。

因此当两个对象的内容相同而地址不同,仍被认为是两个不同得对象。因此在这种情况下,去HashSet或者HashMap中查找一个对象是否存在时,即使该集合中已经存放着该元素,但还是会返回false,因为这两个对象的地址是不相等的。这便是覆写equals方法为什么一定要覆写hashCode方法的原因。

HashSet与TreeSet的异同

相同点:

  • 都是Set接口的实现类,都不能存放重复的值。
  • HashSet和TreeSet都是异步的非线程安全的,在遍历时,若改变元素的值会产生
    fail-fast(并发修改异常)。

不同点:

  • HashSet底层是HashMap,而TreeSet底层是TreeMap。
  • HashSet中可以存放null值,而TreeSet中不能存放null值。
  • HashSet中元素无序存储(但非随机存放的,由hash值而定),而TreeSet中的元素是有序存放的。
TreeSet排序分析

对于TreeSet可以实现有序存储,也没有那么神秘。只是与两个接口有关系而已,而对于String,Integer等类,都实现了Comparable接口,并覆写了compareTo方法。

  • Comparable接口:实现内部排序。
  • Comparator接口:实现外部排序。

详情请参考

Java 学习总结—比较器

而对于实现了比较器的TreeSet而言,就与equals方法和hashCode方法没有关系,覆写或者不覆写都无关紧要,因为此时判断两个对象相等是根据比较器中的方法是否返回0而定的,返回0,则表示两个对象相等,否则就是不想等。

代码演示:

自定义类,采用外部排序,因此不必实现Comparable接口

public class Person {
    private static int num = 0;
    private String name;
    private Integer age;
    public Person(){}
    public Person(String name,Integer age){
        this.age = age;
        this.name = name;
    }

    public static int getNum() {
        return num;
    }

    public static void setNum(int num) {
        Person.num = num;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试代码:构造方法中通过Lambda表达式传入比较器

public static void testTreeSet(){
    TreeSet<Person> set = new TreeSet<>((p1,p2)->{return p1.getAge() - p2.getAge();});  
    set.add(new Person("Jack",20));
    set.add(new Person("Lucy",18));
    set.add(new Person("Tom",22));
    set.add(new Person("Danny",20));
    System.out.println(set);
    System.out.println(set.contains(new Person("Jack",20)));
}

运行结果:
在这里插入图片描述
此时出现很滑稽的一幕,只要两个Person对象的年龄相同,就当作是同一个对象,这是由自定义的比较器而定的。也没有啥奇怪的。

总结

TreeSet的元素相同判断是根据比较器中自定义的方法而定的。而不再是equals和hashCode方法。

猜你喜欢

转载自blog.csdn.net/weixin_43213517/article/details/89607532