Java中的Set接口及实现类

238 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

Java中的Set接口及实现类

掌握:

       Set接口及其实现类的特点及相关方法的用法

HashSet集合存储并遍历字符串元素:

Collection

       --List

              有序(存储顺序和取出顺序一致),可重复

       --Set

              无序(存储顺序和取出顺序不一致),唯一

HashSet:

       它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。

       注意:

              虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,如果你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。

       HashSet:存储字符串并遍历

       问题: 为什么存储字符串的时候,字符串内容相同的只存储了一个呢?

       通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。

步骤:

       首先比较哈希值

       如果相同,继续走,比较地址值或者走equals()

       如果不同,就直接添加到集合中  

按照方法的步骤来说:   

       先看hashCode()值是否相同

       相同:继续走equals()方法

              返回true:说明元素重复,就不添加

              返回false:说明元素不重复,就添加到集合

       不同:就直接把元素添加到集合

       如果类没有重写这两个方法,默认使用的Object()。一般来说不相同。

       而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。

    HashSet<String> strings=new HashSet<String>();
    strings.add("hello");
    strings.add("world");
    strings.add("java");
    strings.add("world");
    strings.add("java");
    Iterator<String> iterator = strings.iterator();
    System.out.println("-----迭代器---------");
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
    System.out.println("------增强for--------");
    for (String s : strings) {
        System.out.println(s);
    }
    System.out.println("------forEach--------");
    strings.forEach(s->System.out.println(s));

使用HashSet集合存储自定义对象,并保证元素的唯一性:

要求:如果两个对象的成员变量值都相同,则为同一个元素。

       目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。

       而这两个方法我们在自定义类中没有重写,所以,默认使用的是Object类。

       这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。

       如果你认为对象的成员变量值相同即为同一个对象的话,你就应该重写这两个方法。

自动生成的快捷键:按 alt + shift + s , 然后按h

生成的代码与自己定义的类属性有关。

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        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 != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

TreeSet集合保证元素排序和唯一性的原理

唯一性:是根据比较的返回是否是0来决定。

排序:

        A:自然排序(元素具备比较性)

              让元素所属的类实现自然排序接口 Comparable

       B:比较器排序(集合具备比较性)

              让集合的构造方法接收一个比较器接口的子类对象 Comparator

比较器排序有三种方式

       方式1:

              定义一个类实现Comparator接口,将该类对象作为TreeSet构造方法的参数TreeSet<t> ts=new TreeSet<t>(new MyComparator());

       方式2:

              定义一个类实现Comparator接口,将该类对象作为TreeSet构造方法的参数,该类放在测试类一个文件

       方式3:

              在TreeSet类带参构造方法中定义一个实现Comparator接口的匿名内部类