精华内容
下载资源
问答
  • set实现类各个区别
    2014-05-18 15:45:44

    Set(interface)

      存入Set 的每个元素都必须是唯一的,因为Set不保存重复的元素。假如Set的元素必须定义equals方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。


    HashSet*

      为快速查找为设计的Set。催乳HashSet的元素必须定义hashCode()。如果你没有其他限制,这是你默认的选择,因为它对速度进行了优化。


    TreeSet

      保持次序的Set,底层为树结构,使用它可以从Set中T恤有序的序列。元素必须实现Comparable接口。


    LinkedHashSet

      具有HshSet的查询速度,且内部使用列表维护元素的次序(插入顺序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。元素也必须定义hashCOde()定义。

    更多相关内容
  • Java中三种Set实现类的用法和区别

    千次阅读 2020-03-19 23:56:45
    Java为开发者提供了大量的...Java中提供了HashSet、TreeSet、LinkedHashSet三种常用的Set实现,以下具体分析它们的用法和性能。 我们使用Set的原因是Set集合不包含重复元素,HashSet、TreeSet和LinkedHashSet三种类...

    Java为开发者提供了大量的工具类,这给开发人员带来了很大方便,但是选择多了也有困扰,究竟用哪个类;我想选择什么,一是看自己具体需求,二是类本身的性能和用法;Java中提供了HashSet、TreeSet、LinkedHashSet三种常用的Set实现,以下具体分析它们的用法和性能。

    我们使用Set的原因是Set集合不包含重复元素,HashSet、TreeSet和LinkedHashSet三种类型什么时候使用它们,使用哪个这是一个很重要的选择性问题,正确的选择会大大提升程序运行效率;总结一下,如你的需求是要一个能快速访问的Set,那么就要用HashSet,如果你要一个排序Set,那么你应该用TreeSet,如果你要记录下插入时的顺序时,你应该使用LinedHashSet。把握这几个原则,是不是选择起来就简单多了。

    Set接口的特性,Set接口继承了Collection接口,Set集合中不能包含重复的元素,每个元素必须是唯一的,你只要将元素加入set中,重复的元素会自动移除

     

    HashSet

     

    HashSet结构图

     

     

    TreeSet

     

    TreeSet结构图

     

     

     

    LinkedHashSet

     

    LinkedHashSet结构图

    展开全文
  • Set接口及其实现类

    千次阅读 2019-05-12 00:09:27
    在之前的博客中讲解到了Collection接口下的一个子接口List,现在对Collection接口的另外一个子接口进行讲解 ...HashSet是Set接口的实现类,元素唯一,无序(存取顺序不一致) HashSet 底层数据结构...

    在之前的博客中讲解到了Collection接口下的一个子接口List,现在对Collection接口的另外一个子接口进行讲解

    集合框架(Set集合概述及特点)

    Set集合概述及特点: 通过API查看得知:Set就是一个不包含重复元素的Collection

    集合框架(HashSet存储字符串并遍历)

    HashSetSet接口的实现类,元素唯一,无序(存取顺序不一致)
    HashSet 底层数据结构是哈希表:元素为链表的数组,具有链表和数组的特点 像新华字典(JDK1.7)

    HashSet的构造方法:

    1. HashSet() 构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是
      0.75。 就是 当集合被使用达到了初始容量的0.75是就会对原列表进行扩充
    2. HashSet(Collection<? extends E> c) 构造一个包含指定 collection 中的元素的新 set

    代码示例:

    package org.westos.java;
    
    import java.util.HashSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 09:11
     */
    public class MyTest {
        public static void main(String[] args) {
            HashSet<String> set = new HashSet<>();
            set.add("q");
            set.add("d");
            set.add("v");
            set.add("v");
            set.add("t");
            set.add("p");
            for (String s : set) {
                System.out.println(s);
            }
        }
    }
    

    在上述代码中使用HashSet类的空参构造来创建了一个Set对象,在该对象中一次添加一些字符串,运行上述代码,可知运行结果为:

    p
    q
    d
    t
    v
    

    从上述结果可以看出,集合中的内容是无序的即存取顺序不一致,而且重复的元素也被去除

    集合框架(HashSet保证元素唯一性)

    HashSet 底层数据结构是哈希表. HashSet 不是线程安全的,但是效率高, 集合元素可以是 null

    哈希表:是一个元素为链表的数组,综合了数组和链表的优点 (像新华字典一样) (JDK1.7之前)

    HashSet唯一性无序性的实现步骤:

    1. 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象hashCode() 方法来得到该对象的
      hashCode 值,

    2. 然后根据 hashCode 值决定该元素所处的对象数组中的索引值,确定完成后

    3. 确定我要放入集合的元素的值是否和该索引处的链表上的各个元素相等,如果不相等,就将该元素链接在表尾;如果相等,就不会链接, 通过这样就确保了集合中的元素的唯一性,

    4. 也正是因为在存的过程中会通过哈希值来确定在数组位置的索引,所以实现的无序性

    HashSet 集合判断两个元素相等的标准:
    两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

    结论:HashSet 保证元素唯一性是靠元素重写hashCode()equals()方法来保证的,如果不重写则无法保证。

    源码查看:

    HashSet<Integer> set = new HashSet<>();
    set.add(100);
    

    在上述代码中长按Ctrl键将鼠标放在add方法上可以查看add方法的实现,可以查看到如下内容:

    public boolean add(E e) {
           return map.put(e, PRESENT)==null;
    }
    

    之后再次长按Ctrl键并将鼠标放置到put方法上,可以查看到put方法的源码

    public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);   //求出了要添加的对象的哈希值,确定了存放在数组的某个区间的位置索引
    }
    

    按照上述方法再次查看putVal方法,可以看到该方法的源码

     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K,V> e; K k;
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))  //调用了添加的对象的equal方法,来比较我要添加的元素和索引处链表上的各个元素的值是否相等
                    e = p;
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                else {
                    for (int binCount = 0; ; ++binCount) {
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;
            if (++size > threshold)
                resize();
            afterNodeInsertion(evict);
            return null;
      }
    

    上述代码调用了要添加的对象的equal方法,自定义类中直接继承Object类的equal方法,但是该方法默认比较的是两个局部变量中所存的地址值,而我们需要对对象中的内容进行比较的话就必须要对该方法进行重写

    在上述代码中讲解了为什么要对equal方法进行重写,下面要讲解为什么对hashCode()方法进行重写
    在下面的代码中:

    public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
    }
    

    在该代码块中长按Ctrl键查看hash方法的源码:

    static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    1. 该方法调用了要添加的对象的hashCode()方法,但是为什么要重写这个方法呢,因为在我们自定义类时,如果我们创建了两个对象,两个对象的成员变量完全相等,但是因为不是相同的对象,所以会有不同的哈希值,但是对用户来说,如果两个对象的成员一样,就会将他们视为同一个对象,就可以将这两个对象中的任意一个对象删除。
    2. 在上面讲到了HashSet 集合判断两个元素相等的标准: 两个对象通过 hashCode() 方法比较相等,并且两个对象的
      equals() 方法返回值也相等,
    3. 根据上面讲到的标准来判断之前提到的两个对象,因为两个对象不一样,所以第一条标准便不满足,这就导致有两个内容完全相等的对象但在计算机判断时时不同的两个对象,所以依然会将重复的元素存入哈希表中,这就不能确保HashSet集合中不存在重复元素,所以必须重写hashCode()方法。
    4. 而且在判断元素是否相等是,不再比较两个局部变量的地址值,而是比较两个元素的内容,所以需要对equal方法进行重写
    5. Integer类和String类已经默认重写了hashCode()equals()方法,所以在上述的代码示例中才能实现去重的功能,如果要存储自定义类的对象,就要进行这两个方法的重写。
    6. 而合理的重写hashCode()方法可以减少碰撞次数,就是在同一条链表上比较各个元素内容是否相等的次数

    集合框架(HashSet存储自定义对象保证元素唯一性)

    通过上面的讲解,可以基本理解HashSet实现元素唯一性的步骤。看看下面的代码:

    package org.westos.java;
    
    import java.util.HashSet;
    import java.util.Objects;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 09:22
     */
    public class MyTest {
        public static void main(String[] args) {
            Student s1 = new Student("王五", 25);
            Student s2 = new Student("王五", 25);
            Student s3 = new Student("王五", 25);
            Student s4 = new Student("王五", 252);
            Student s5 = new Student("王五2", 235);
            Student s6 = new Student("王五3", 25);
            Student s7 = new Student("王五4", 2665);
            Student s8 = new Student("王五5", 285);
            Student s9 = new Student("王五6", 285);
            Student s10 = new Student("王五7", 255);
            HashSet<Student> hashSet = new HashSet<>();
            hashSet.add(s1);
            hashSet.add(s2);
            hashSet.add(s3);
            hashSet.add(s4);
            hashSet.add(s5);
            hashSet.add(s6);
            hashSet.add(s7);
            hashSet.add(s8);
            hashSet.add(s9);
            hashSet.add(s10);
            for (Student student : hashSet) {
                System.out.println(student.getName() + "==" + student.getAge());
            }
        }
    }
    
    class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        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 boolean equals(Object o) {              //对equal方法的重写在之前的Object类的博客中进行过详细的讲解,读者可以自行查阅
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age &&
                    Objects.equals(name, student.name);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    
    }
    

    在上述代码中重写了那两个方法,实现了集合中元素的唯一性,代码运行结果如下:

    王五4==2665
    王五==25
    王五3==25
    王五6==285
    王五5==285
    王五7==255
    王五==252
    王五2==235
    

    但是代码依然无序,即元素存取顺序不一致

    集合框架(HashSet存储自定义对象保证元素唯一性图解及代码优化)

    在这里插入图片描述上述代码如果不对hashCode()方法进行重写,那么每个对象有不同的哈希值,所以也会被存放在不同的索引处,所以无法确保元素唯一;我们对该方法进行简单的重写,让他只返回哈希值0,这样所有元素的哈希值都一样,就会都被存放在数组的索引0处,但是也导致要确保元素唯一性就必须让链表末尾的元素和该链表中的每一个元素进行比较,这样也就是之前提到的增加了碰撞次数,所以可以对hashCode()方法进行合理的重写来减少碰撞次数,这里我们直接使用Java提供的自带的重写后的方法

    集合框架(LinkedHashSet的概述和使用)

    底层数据结构有两个: 链表哈希表

    链表保证有序 哈希表保证元素唯一
    注意:这里的有序是指元素的存取顺序一致

    代码示例:

    package org.westos.demo3;
    
    import java.util.LinkedHashSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 10:17
     */
    public class MyTest {
        public static void main(String[] args) {
            LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
            linkedHashSet.add("A");
            linkedHashSet.add("B");
            linkedHashSet.add("D");
            linkedHashSet.add("E");
            linkedHashSet.add("C");
            linkedHashSet.add("E");
            linkedHashSet.add("C");
            linkedHashSet.add("E");
            linkedHashSet.add("C");
    
            for (String s : linkedHashSet) {
                System.out.println(s);
            }
        }
    }
    

    运行程序,可以看到运行结果为:

    A
    B
    D
    E
    C
    

    这样既能保证元素的唯一性,也能保证元素的存取顺序一致

    集合框架(TreeSet的概述和引用)

    TreeSet集合的特点: 底层数据结构是二叉树,集合中元素唯一,并且可以对元素进行排序
    排序:

    • 自然排序

    • 使用比较器排序

    到底使用的是哪一种的排序取决于构造方法

    • 空参构造,那么就使用的是自然排序;
    • 有参构造,可以使用比较器来排序

    代码示例:

    package org.westos.java;
    
    import java.util.TreeSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 10:20
     */
    public class MyTest {
        public static void main(String[] args) {
            TreeSet<Integer> treeSet = new TreeSet<>();
            treeSet.add(20);
            treeSet.add(18);
            treeSet.add(23);
            treeSet.add(22);
            treeSet.add(17);
            treeSet.add(24);
            treeSet.add(19);
            treeSet.add(18);
            treeSet.add(24);
            for (Integer integer : treeSet) {
                System.out.println(integer);
            }
        }
    }
    

    在上述代码中给集合中添加了多个元素,运行结果如下:

    17
    18
    19
    20
    22
    23
    24
    

    可知,集合中的元素唯一且进行了排序

    注意:使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现Comparable接口并重写comPareTo方法,根据此方法的返回值的正负0 来决定元素在二叉树的位置,否则无法进行自然排序,那为什么上述代码没有实现Comparable接口呢,那是因为Integer类已经实现了该接口,并且重写了里面的抽象方法,如果是自定义类那么就必须实现该接口

    代码示例2:

    package org.westos.java;
    
    import java.util.TreeSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 10:31
     */
    public class MyTest {
        public static void main(String[] args) {
            //按照学生的年龄大小来排序
            Student s1 = new Student("王五", 21);
            Student s11 = new Student("王五", 21);
            Student s123 = new Student("王五3333333333", 21);
            Student s2 = new Student("王五", 22);
            Student s3 = new Student("王五111", 25);
            Student s4 = new Student("王五3333", 252);
            Student s5 = new Student("王五22222222222", 235);
            Student s6 = new Student("王五3", 25);
            Student s7 = new Student("王五2222222224", 2665);
            Student s8 = new Student("王五5", 288);
            Student s9 = new Student("王五22226", 285);
            Student s10 = new Student("王五7", 255);
            TreeSet<Student> treeSet = new TreeSet<>();
            treeSet.add(s1);
            treeSet.add(s11);
            treeSet.add(s2);
            treeSet.add(s3);
            treeSet.add(s4);
            treeSet.add(s5);
            treeSet.add(s6);
            treeSet.add(s7);
            treeSet.add(s8);
            treeSet.add(s9);
            treeSet.add(s10);
            treeSet.add(s123);
            for (Student student : treeSet) {
                System.out.println(student);
            }
    
    
        }
    }
    
    class Student implements Comparable<Student> {
        private String name;
        private int age;
    
        public Student() {
        }
    
        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 compareTo(Student s) {
            //比较逻辑是按照年龄大小来排序
            int num = this.age - s.age;
            //当年龄相同不能说明他是同一个对象,还得比较姓名
            int num2 = num == 0 ? this.name.compareTo(s.name) : num;
            return num2;
        }
    }
    

    在上述代码中,我们自定义了Student类,并且让该类实现了Comparable接口并重写了compareTo方法,下面来详细讲解如何重写compareTo方法

    二叉树我们会先将第一个元素设置为根结点,因为我们是按照学生的年龄来对Student对象进行排序,所以会把第二个元素的年龄与根节点的年龄进行比较,如果比第一个大,就放置在第一个结点的右边,如果比第一个小,就放在左边,如果一样就不储存;存储完成后,后续的元素重复执行上述步骤,直到存储完毕。下面是在 TreeSet集合中存储Integer类的数据时的图示:
    在这里插入图片描述在上图中,如果要再次存储24,就会和20比较,将24存到20右边,然后又会用2423这个结点进行比较,2423大,所以就存在23右边,但是发现23右边的结点已经存在24就不会进行存储,保证了集合中元素的唯一性有序性

    但是在上述代码示例中如果要重写compareTo时候,可能会发生一些特殊情况:
    如果两个学生姓名不一样,但是成绩一样,在重写的方法里面只写对成绩进行比较,那么就会将这两个不一样的对象认为是同一个对象,不会存储后面的对象,这是一种用户不想看到的情况,那么如何解决这个问题呢?

    我们还需要对姓名进行比较,如果成绩一样而且姓名也一样,就认定两个对象完全一样(但是在现实生活中也会有可能发生这种情况,在这里不再考虑,主要理解概念),不保存后面的对象,这样就不会发生元素缺失的情况,代码实现如下:

    @Override
    public int compareTo(Student s) {
           //比较逻辑是按照年龄大小来排序
           int num = this.age - s.age;
           //当年龄相同不能说明他是同一个对象,还得比较姓名
           int num2 = num == 0 ? this.name.compareTo(s.name) : num;
           return num2;
    }
    

    compareTo(String anotherString) :按字典顺序比较两个字符串。如果参数字符串等于此字符串,则返回值 0;如果此字符串按字典顺序小于字符串参数,则返回一个小于 0 的值;如果此字符串按字典顺序大于字符串参数,则返回一个大于 0 的值。

    1. 如果num != 0,肯定不是同一个对象,可以将后面的元素存入二叉树中
    2. 如果num == 0则执行 int num2 = num == 0 ? this.name.compareTo(s.name) : num;,在num == 0时,比较后面元素的姓名和现在的元素的姓名,如果相等 this.name.compareTo(s.name)执行后返回1;否则返回0,并且赋给num2
    3. 后面的num并不会起作用,只是为了让三目运算符的格式完整,因为既然执行这条语句肯定num == 0是成立的,肯定只执行int num2 = num == 0 ? this.name.compareTo(s.name) : num;语句,如果后面元素的姓名和现在的元素的姓名相等num2=0, 否则num2正或负,然后根据返回的num2的值来判断是不存入二叉树还是存放在结点的右边还是左边
    4. 通过上述的代码便可以实现集合中元素的有序唯一
    5. 需要注意的是TreeSet集合不允许存null

    集合框架(TreeSet存储自定义对象并遍历练习)

    代码示例:

    package org.westos.java;
    
    
    import java.util.TreeSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 10:31
     */
    public class MyTest {
        public static void main(String[] args) {
            //按照学生的年龄大小来排序
            Student s1 = new Student("王五", 21);
            Student s222222 = new Student("李四", 21);
            Student s11 = new Student("王五", 22);
            Student s123 = new Student("王五3333333333", 21);
            Student s2 = new Student("王五", 22);
            Student s3 = new Student("王五111", 25);
            Student s4 = new Student("王五3333", 252);
            Student s110 = new Student("王五3333", 253);
            Student s5 = new Student("王五22222222222", 235);
            Student s6 = new Student("王五3", 25);
            Student s7 = new Student("王五2222222224", 2665);
            Student s8 = new Student("王五5", 288);
            Student s9 = new Student("王五22226", 285);
            Student s10 = new Student("王五7", 255);
            //使用的是自然排序:
            TreeSet<Student> treeSet = new TreeSet<>();
            treeSet.add(s1);
            treeSet.add(s11);
            treeSet.add(s2);
            treeSet.add(s3);
            treeSet.add(s4);
            treeSet.add(s5);
            treeSet.add(s6);
            treeSet.add(s7);
            treeSet.add(s8);
            treeSet.add(s9);
            treeSet.add(s10);
            treeSet.add(s123);
            treeSet.add(s222222);
            treeSet.add(s110);
            for (Student student : treeSet) {
                System.out.println(student);
            }
    
    
        }
    }
    class Student implements Comparable<Student> {
        private String name;
        private int age;
    
        public Student() {
        }
    
        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 compareTo(Student s) {
            //比较姓名的长度
            int num = this.name.length() - s.name.length();
            //姓名长度一样后,还得比较姓名的内容
            int num2 = num == 0 ? this.name.compareTo(s.name) : num;
            //姓名长度一样,姓名内容一样,还得比较年龄
            int num3 = num2 == 0 ? this.age - s.age : num2;
            return -num3;
        }
    }
    

    上述代码实现的需求是:

    1. 先按照学生姓名的长度进行排序,
    2. 如果长度一样按姓名字典顺序进行排序,
    3. 如果上述二者还一样就按照年龄进行排序

    上述代码运行结果为:

    Student{name='王五22222222222', age=235}
    Student{name='王五3333333333', age=21}
    Student{name='王五2222222224', age=2665}
    Student{name='王五22226', age=285}
    Student{name='王五3333', age=253}
    Student{name='王五3333', age=252}
    Student{name='王五111', age=25}
    Student{name='王五7', age=255}
    Student{name='王五5', age=288}
    Student{name='王五3', age=25}
    Student{name='王五', age=22}
    Student{name='王五', age=21}
    Student{name='李四', age=21}
    

    通过运行结果可知实现了需求

    集合框架(TreeSet比较器排序的原理及代码实现)

    在创建TreeSet集合时,如果使用有参构造,传递一个比较器,便可实现排序
    代码示例:

    package org.westos.java;
    
    import java.util.Comparator;
    import java.util.TreeSet;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 11:15
     */
    public class MyTest {
        public static void main(String[] args) {
            MyComparator myComparator = new MyComparator();
            TreeSet<Student> treeSet = new TreeSet<>(myComparator);    //TreeSet有参构造
            treeSet.add(new Student("王五", 21));
            treeSet.add(new Student("王五1", 212));
            treeSet.add(new Student("王五2", 241));
            treeSet.add(new Student("王五3", 2771));
            treeSet.add(new Student("王五4", 251));
            treeSet.add(new Student("王五5", 2661));
            treeSet.add(new Student("王五6", 2661));
            treeSet.add(new Student("王五7", 217));
            for (Student student : treeSet) {
                System.out.println(student);
            }
        }
    }
    
    
    class MyComparator implements Comparator<Student> {      //自定义类来实现比较器的实例化
        @Override
        public int compare(Student s1, Student s2) {
            //按照年龄来排
            int num = s1.getAge() - s2.getAge();
            int num2=num==0?s1.getName().compareTo(s2.getName()):num;
            return num2;
        }
    }
    class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        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 +
                    '}';
        }
    
    }
    
    1. 因为比较器是个接口,不能实例化,可以自定义一个类来实现Comparator接口,并且重写该接口中的compare方法,重写的内容和之前讲过的无参构造重写compareTo方法重写逻辑一样,这样比较器便可以实例化
    2. 之后创建一个比较器对象,将该比较器对象传入TreeSet有参构造来说实现唯一排序
    3. 元素在二叉树中的存储方式和之前讲过的无参构造相同

    当然,因为比较器是个接口,可以使用匿名内部类来实现,而且可以用到其他类的成员方法中:

    代码示例2:

    package org.westos.demo8;
    
    import java.util.ArrayList;
    import java.util.Comparator;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 11:27
     */
    public class MyTest {
        public static void main(String[] args) {
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(21000000);
            integers.add(2210);
            integers.add(2130);
            integers.add(2150);
            integers.add(2150);
            integers.add(21770);
            integers.add(21550);
            integers.sort(new Comparator<Integer>() {
                @Override
                public int compare(Integer a, Integer b) {
                    return a-b;
                }
            });
    
            System.out.println(integers);
        }
    }
    

    这里让Integer类来实现了比较器的匿名内部类,实现排序,匿名内部类总的逻辑与上面讲到的相同

    代码示例3:

    package org.westos.demo8;
    
    import java.util.Arrays;
    import java.util.Comparator;
    
    /**
     * @Author: Administrator
     * @CreateTime: 2019-05-11 11:29
     */
    public class MyTest2 {
        public static void main(String[] args) {
            Integer[] arr = {2, 4, 0, 1, 40, 24};
            // Arrays.sort(arr);
            Arrays.sort(arr, new Comparator<Integer>() {
                @Override
                public int compare(Integer a, Integer b) {
                    return -(a - b);
                }
            });
            System.out.println(Arrays.toString(arr));
        }
    }
    

    这里让 Arrays类的sort方法实现了比较器接口的匿名内部类,实现排序,内部类内容同上

    展开全文
  • Set集合各个实现类的基础概念

    千次阅读 2018-07-03 13:56:59
    Set集合各种实现类性能分析 HashSet 是基于Hash算法来实现的,功能是能快速查到到检索的对象,hash算法在于速度,查询某个元素是根据hashCode()值计算出存储位置从而找得的不会记住添加顺序.添加顺序位置随机...
                                                     Set集合各种实现类性能分析         
    HashSet
    •  是基于Hash算法来实现的,功能是能快速查到到检索的对象,hash算法在于速度,查询某个元素是根据hashCode()值计算出存储位置从而找得的
    • 不会记住添加顺序.添加顺序位置随机
    • 不会添加重复元素,在同一个集合输入相同元素,add()方法返回false,且新元素不会加入
    • HashSet类似于HashMap的key,把key封装起来就HashSet,
    • HashSet访问元素也是根据hashCode()的值来快速定位
    • HashSet比较两个元素相等的标准是通过equals()方法与hashCode( )方法比较的对象返回值相等,但如果两个元素的equals相等,hashCode()不相等也是会添加成功
     
            代码如下:
    public static void main(String[] args) {
           HashSet<String> set=new HashSet<String>();
           set.add("小陈");
           set.add("小红");
           set.add("小花");
           set.add("小明");
           set.add("小亮");
           //并不会添加相同元素
           set.add("小陈");
           for (String obj: set) {
                 System.out.println(obj);
           }
    }             

    结果是:   小陈 小明 小亮 小红 小花    
    可以看来并不会添加相同元素进来



    LinkedHashSet
    •   也是根据hashCode()来访问元素位置,但同时使用链表来维护元素的次序,使元素维持插入的顺序保存起来,遍历输出后也是按照添加顺序输出
    • 也不允许集合元素重复。
    • 因为需要维持元素的插入顺序,性能比HashSet低
    • 访问Set里的全部元素有很好的性能,因为它以链表来维护顺序
    代码如下
    public static void main(String[] args) {
           LinkedHashSet itn=new LinkedHashSet();
           itn.add(5);
           itn.add(2);
           itn.add(8);
           itn.add(10);
           Iterator abn=itn.iterator();
    //使用lambda表示式来来遍历集合,减少过多的代码
           abn.forEachRemaining(obj ->System.out.println("排序元素是:"+obj));
    }

    结果是:
    元素的集合是5
    元素的集合是2
    元素的集合是8
    元素的集合是10

    TreeSet
    • 要求内部元素实现Comparable接口
    • 使用树结构实现(红黑树),集合中的元素进行排序
    • 其中自然排序与自定义排序

    代码如下
    public static void main(String[] args) {
            TreeSet itn=new TreeSet();
            itn.add(65);
            itn.add(30);
            itn.add(34);
            itn.add(21);
            Iterator st=itn.iterator();
    //使用lambda表示式来来遍历集合,减少过多的代码
            st.forEachRemaining(ele ->System.out.println("元素的集合是"+ele));
     }

    结果是:
    元素的集合是21
    元素的集合是30
    元素的集合是34
    元素的集合是65
    总结:Set集合性能分析 HashSet性能是比TreeSet好(在添加查询等方面,因为TreeSet需要在额外的红黑树来维持排序,只有当需要保持一个排序的Set才使用TreeSet,不然都使用HashSet
    LinkedHashSet对于普通的插入与删除比HashSet慢,但有了链表,遍历LinkedHashSet会快很多
    展开全文
  • java集合中各个接口与实现类区别

    千次阅读 2016-04-09 20:39:06
    List接口是有序集合、元素可以重复,次序是List接口最重要的特点,他是以元素的添加的顺序作为集合的顺序,因此List的实现类中有可以通过来操作集合元素的方法。其中ArrayList底层是通过数组实现的,数组的初始长度...
  • Java Web小课程2——写实体类,写接口,写实现类,测试实现类
  • java反射获取所有接口实现类

    千次阅读 2022-04-25 13:55:17
    继承关系为:IMetadataDict.class 为接口,各个枚举类实现这个接口,这样就不会将无关的枚举也包含进去。 依赖及测试方法如下: org.reflections reflections 0.10.2 public static void main(String[] args) ...
  • java中list,set,map集合的区别,及面试要点

    万次阅读 多人点赞 2019-02-28 12:33:25
    (图一) 1.面试题:你说说collection里面有什么子类。 (其实面试的时候听到这个问题的时候,你要知道,面试官是想考察List,Set) 正如图一,list和set实现了collection接口的。 (...
  • Java集合基础(List,Set,Map)

    千次阅读 2017-09-16 17:12:26
    集合类简介Java的集合类主要由两个接口派生而出:Collection和Map,这两个接口又包含了一些接口或实现类。 一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些...
  • java中Map有哪些实现类和使用场景

    万次阅读 多人点赞 2018-05-25 21:02:38
    Java中的map是一个很重要的集合,他是一个接口,下面继承它实现了多个实现类,这些类各有千秋,各自有个各自的优点和缺点,先上图。 map的主要特点是键值对的形式,一一对应,且一个key只对应1个value。其常用的map...
  • Set最大的特性就是不允许在其中存放的元素是重复的。接下来通过本文给大家分享java set常用方法和原理分析,需要的的朋友参考下吧
  • Set集合与List集合的区别

    万次阅读 2019-06-17 11:00:21
    区别: 1:**Set 里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象,**即假设 Set 集合中有了一个 A 对象,现在我要向 Set 集合再存入一个 B 对象,但 B 对象与 A 对象 equals ...
  • java中多线程之CAS详解     什么是volatile volatile是JVM提供的轻量级同步机制 ...jmm是一种抽象的概念,并不真实存在,它描述的是一种规范,通过这种规范定义了程序中的各个变量的访问形式。(仔细读
  • List、Map、Set 有什么区别

    千次阅读 2018-08-27 17:11:23
    Set里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象 ,即假设Set集合中有了一个A对象,现在我要向Set集合再存入一个B对象,但B对象与A对象equals相等,则B对象存储不进去,所以...
  • JavaScript巧用Object的get和set方法实现js变量的动态监听咳咳,现在开始打起精神了哈! 话说怎么突然想起写这个了呢?事情是这样的,且听小编给你慢慢道来 前段时间VUE写的有些累了,想换换脑子,就开始学一个js写...
  • java中set、list和map的使用方法实例

    热门讨论 2011-10-04 19:27:31
    // set容器接口的实现类有HashSet和 LinkedHashSet两个 // HashSet不保证迭代顺序, LinkedHashSet按照元素插入的顺序迭代. // 学习List对象容器的使用 // List容器中的对象允许重复 // 常用的list接口的实现类有...
  • 对于BoardDao和CuisineDao的处理接口和实现类,除了定义自己的特有方法外,其他基本功能的CRUD方法都一样,只是操作的实体对象不一样。为了代码的复用,简化代码,我们可以将公共的CRUD方法提取到BaseDao中,只需要...
  • 根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品种类的存储需求。Set 可以被用来过滤在其他集合中存放的元素,从而得到一个没有包含重复新的集合。2. 常用方法按照定义,Set 接口继承 Collection...
  • c++ unordered_set的用法

    千次阅读 多人点赞 2022-02-23 12:01:14
    C++ 11 为 STL 标准库增添了 4 种无序(哈希)容器, 本节讲解 unordered_set 容器 unordered_set 容器,可直译为“无序 set 容器”,即 unordered_set 容器和 set 容器很像,唯一的区别就在于 set 容器会自行对存储...
  • stm32 实现定时器

    2017-03-14 15:21:36
    在工程当中,可以在各个文件灵活中使用定时器功能,不用考虑定时中断的位置和设置,就像C#使用定时器一样,申请一个定时器的,所有的定时即可在当前文件中实现
  • 而我们在介绍Set集合前,先介绍Java中多个原生的Map容器,是因为Java中多个原生的Set集合都依赖于对应的Map容器进行实现。例如后文将要介绍的HashSet集合,其内部主要依赖于HashMap进行实现,前者的子类...
  • 直接看代码吧,只要执行子类的mk方法,就可以 一次性set多个值 /* * 文 件 名: BaseBean.java * 版 权: * 描 述: * 修 改 人: nanshouxiao * 修改时间: 2015年8月19日 * 跟踪单号: * 修改单号: * ...
  • 问题:因为后台中对酒店及对应房间类型有数量控制,导入之前,需要统计出Excel表中的各个酒店的不同类型房间的数量, 避免人为填写的Excel数据有误 前缀太多,现在让我们直奔主题吧!!!。。。。。。 技术...
  • java各种集合类区别

    万次阅读 多人点赞 2019-03-27 17:54:45
    集合接口分为:Collection和Map,list、set实现了Collection接口 List总结: 可以重复,通过索引取出加入数据,顺序与插入顺序一致,可以含有null元素 ArrayList:底层数据结构使数组结构array,...
  • 文章目录概述关于wait set 概述 官方指导: https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html 或者: ... 关于wait set Eve...
  • 1 集合框架 1.1 集合框架概述 ... 举例来说,假设要存储许多雇员,不同的雇员的区别仅在于雇员的身份证号。我们可以通过身份证号来顺序存储每个雇员,但是在内存中实现呢?是不是要准备足够的内存来存储1000个雇
  • Java中的Set集合

    千次阅读 2013-09-07 11:29:29
    根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品种类的存储需求。Set 可以被用来过滤在其他集合中存放的元素,从而得到一个没有包含重复新的集合。   2. 常用方法  按照定义,Set
  • 基于支持向量机的图像分类(下篇:MATLAB实现

    万次阅读 多人点赞 2018-04-11 00:19:20
    摘要:本文通过图文详细介绍如何利用支持向量机对图像进行分类,经过上篇文章对原理的介绍,这里介绍利用MATLAB编程实现。后续章节将介绍的主要部分有: 图片数据集整理 特征提取 SVM训练与测试 分类结果...
  • 方法的基本原则 ④Eclipse/IDEA工具里hashCode()的重写 ⑤Set实现类之二:LinkedHashSet ⑥Set实现类之三:TreeSet ⑦排 序—自然排序 ⑧排 序—定制排序 ⑨练习:在List内去除重复数字值,要求尽量简单 六、Map接口...
  • java中的各种集合排序之set中TreeSet集合排序

    万次阅读 多人点赞 2019-05-03 15:06:01
    1.软件开发过程中集合排序是比较强大的功能,会使用集合Map、Set、List实现排序功能,知道匿名内部Comparator很关键,搞清楚集合排序的性能开销,排序遇到的坑以及解决的方法,注意下面的例子都是JDK1.8的用法。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 352,995
精华内容 141,198
关键字:

set实现类各个区别