• JAVA集合03_HashSet、LinkedHashSet概述、TreeSet自然顺序、比较器顺序


    ①. HashSet的概述

    • ①. 无序性!=随机性(正在的无序性是指元素在底层存储的位置是无序的)

    • ②. 不可重复性:当向set中添加进相同的元素的时候,后面的这个不能添加进去

    • ③. 没有带索引的方法,所以不能用普通for循环遍历

    • ④. 底层数据结构是哈希表

    		HashSet<String>hs=new HashSet<>();
    		boolean b1=hs.add("a");
    		boolean b2=hs.add("a");
    		hs.add(null);
    		//[null, a]
    		System.out.println(hs);  //HashSet的继承体系中,有重写toString()方法
    		System.out.println(b1);//true
    		System.out.println(b2);//false
    		//只要能用迭代器迭代的,就可以使用增强for循环遍历
    		for(String str:hs){
    		    System.out.println(str);//[null,a]
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ②. 哈希值的介绍

    • ①. 哈希值是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

    • ②. Object类中有一个方法可以获取对象的哈希值
      public int hashCode():返回对象的哈希码值

    • ③. 特点:

    1. 同一个对象多次调用hashCode() 方法返回的哈希值是相同的
    2. 默认情况下,不同对象的哈希值是不相同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
    • ④. 哈希值原理

    在这里插入图片描述

    • ⑤. 自定义对象的唯一性
    1. 要求添加进Set中的元素所在的类,一定要重写equal()和 hashCode()方法,进而保存不可重复性
    2. hashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)
    3. equals():属性相同返回true,属性不同返回false,返回false的时候就存储
    [ 掌握关于equals方法和hashCode方法底层实现原理 ]
        /*
      public static int hashCode(Object a[]) {
            if (a == null)
                return 0;
            int result = 1;
            for (Object element : a)
                result = 31 * result + (element == null ? 0 : element.hashCode());
            return result;
        }
       为什么是31?
       1.31是质数,质数是能被1和它本身整除的数
       2.31这个数既不大也不小
       3.31这个数好算,2的5次方-1,向左移动5位数-1
      * */
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;//调用的对象和传入的对象是同一个对象,直接返回true
            if (o == null || getClass() != o.getClass()) return false;//传入的对象为空或者字节码文件不相同,返回false
            Person person = (Person) o;//向下转型
            return age == person.age &&
                    Objects.equals(name, person.name);
            //如果调用对象的年龄和传入对象的年龄 相同并且 调用对象的姓名和传入对象的姓名相同返回true
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • ⑥. HashSet的原理:当HashSet调用add()方法储存对象的时候,先调用对象的hashCode方法得到一个哈希值,然后在集合中查找是否有哈希值相同的对象。如果没有哈希值相同的对象就直接存入集合;如果有哈希值相同的对象,就和哈希值相同对象逐个进行equals()比较,比较结果为false就存入,true则不存

    ③. LinkedHashSet存取有序

    • ①. 哈希表和链表实现的Set接口,具有可预测的迭代次序

    • ②. 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的

    • ③. 由哈希表保证元素唯一,也就是说没有重复的元素

        @Test
    	public void testLinkHashSet(){
    		Set set=new LinkedHashSet();
    		set.add(123);
    		set.add(456);
    		set.add("AAA");
    		set.add("BBB");
    		set.add(null);
    		Iterator iterator=set.iterator();
    		while(iterator.hasNext()){
    			System.out.println(iterator.next());//123 456 AAA BBB null
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • ④.去除list中重复的元素
       //将集合中重复的元素去掉
        @Test
        public void fun7(){
        ArrayList<String>list=new ArrayList<>();
        list.add("AAA");
        list.add("AAA");
        list.add("AAA");
        list.add("AAA");
        list.add("AAA");
        list.add("AAA");
        list.add("BBB");
        list.add("BBB");
        list.add("CCC");
        list.add("CCC");
        getSingle(list);
        // 打印
            System.out.println(list);
        }
    
        public static  void getSingle(ArrayList<String> list) {
            /*LinkedHashSetlhs=new LinkedHashSet<>();
            Iterator iterator = list.iterator();
            while(iterator.hasNext()){
                lhs.add(iterator.next());
            }
    
            for(String lhs2:lhs){
                System.out.print(lhs2+"\t");
            }*/
           //1.创建一个LinkedHashSet集合
            LinkedHashSet<String>lhs=new LinkedHashSet<>();
            //2.将List集合中所有的元素添加到LinkedHashSet集合
            lhs.addAll(list);
            //3.将List 集合中元素清除
            list.clear();
            //4.将LinkedHashSet集合中的元素添加到List集合中
            list.addAll(lhs);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    ④. TreeSet - 排序

    • ①. .TreeSet的特点:元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
    1. TreeSet():根据其元素的自然排序进行排序
    2. TreeSet(Comparator comparator):根据指定的比较器进行排序
    • ②. 没有带索引的方法,所以不能使用普通for循环遍历

    • ③. 由于是Set集合,所以不包含重复元素的集合

    • ④. 向TreeSet添加属性,需要添加同一类型的属性

    ⑤. 自然顺序(Comparable)

    • ①. TreeSet类的add()方法中会把存入的对象提升为Comparable类型

    • ②. 调用对象的CompableTo()方法和集合中的对象比较

    • ③. 根据CompableTo()方法返回的结果进行储存

    • ④. TreeSet底层是一个二叉树,两个叉。小的存储在左边(负数),大的存储在右边(正数),相等就不存0。CompareTo方法,在TreeSet集合如何存储元素取决于compareTo方法的返回值

    1. 返回的0,集合中只有一个元素
    2. 返回-1,集合会将存储的元素倒序
    3. 返回1,集合会怎么存就怎么取
    public class TreeSetDemo {
        public static void main(String[] args) {
            TreeSet<Person> ts=Sets.newTreeSet();
            ts.add(new Person("张三",23));
            ts.add(new Person("李四",13));
            ts.add(new Person("唐志",13));
            ts.add(new Person("王五",43));
            ts.add(new Person("赵六",33));
            //[Person(name=李四, age=13), Person(name=张三, age=23), Person(name=赵六, age=33), Person(name=王五, age=43)]
            System.out.println(ts);
        }
    }
    @Data
    @AllArgsConstructor
    class Person implements Comparable{
        private String name;
        private Integer age;
        //按照年龄从小到大排序
        public int compareTo(Object o) {
            Person p=(Person)o;
            int num=this.age-p.age;//年龄是比较的主要条件
            //int num=-this.age-p.age;//年龄从大到小排序
            return num==0?this.name.compareTo(p.name):num;//姓名是比较的次要条件
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    • ⑤. 按照姓名长度进行排序
    public class TreeSetDemo {
        public static void main(String[] args) {
            TreeSet<Person> ts=Sets.newTreeSet();
            ts.add(new Person("张三",23));
            ts.add(new Person("李四",13));
            ts.add(new Person("李四",12));
            ts.add(new Person("王五",43));
            ts.add(new Person("赵六",33));
            System.out.println('张'+0);//24352
            System.out.println('李'+0);//26446
            System.out.println('王'+0);//29579
            System.out.println('赵'+0);//36213
            //[Person(name=张三, age=23), Person(name=李四, age=12), Person(name=李四, age=13), Person(name=王五, age=43), Person(name=赵六, age=33)]
            System.out.println(ts);
        }
    }
    @Data
    @AllArgsConstructor
    class Person implements Comparable{
        private String name;
        private Integer age;
        
        //按照姓名进行排序,相同按照年龄进行排序
        public int compareTo(Object o) {
            Person p=(Person)o;
            int num=this.name.compareTo(p.name);
            return num==0?this.age-p.age:num;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    ⑥. 比较器顺序(Comparator)

    • ①. 创建TreeSet的时候可以制定一个Comparator接口

    • ②. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序

    • ③. 调用的对象是Comparator接口中compare()方法顺序

    • ④. 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

        @Test
        public void fun4(){
            /*
            需求:将字符串按照长度排序
            * */
            //Comparator c=new CompareByLen();
            //new TreeSet(Comparator );
            TreeSet<String>ts=new TreeSet<>(new CompareByLen());
            ts.add("aaaaaaaa");
            ts.add("z");
            ts.add("wc");
            ts.add("nba");
            ts.add("cba");
            System.out.println(ts);//[n, bb, aaa]
        }
        class CompareByLen /* extends Object*/implements Comparator<String>{//
            @Override
            public int compare(String s1, String s2) {
                //按照字符串长度进行比较
                int num=s1.length()-s2.length();//长度为主要条件
                return num==0?s1.compareTo(s2):num;//内容为次要条件
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    ⑦. 两种排序比较

    • ①. 自然顺序(Comparable)
    1. TreeSet 类的add()方法中会把存入的对象提升为Comparable类型
    2. 调用对象的CompableTo()方法和集合中的对象比较
    3. 根据CompableTo()方法返回的结果进行储存
    • ②. 比较器顺序(Comparator)
    1. 创建TreeSet的时候可以制定一个Comparator接口
    2. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
    3. 调用的对象是Comparator接口中compare()方法顺序
    4. 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
    • ③. 两种方式的区别
    1. TreeSet如果传入Comparator,就优先按照Comparator
    2. TreeSet构造函数什么都不传,默认按照类中Comparable的顺序(没有就报错ClassCastE xception)
    //java.lang.ClassCastException: com.itheima.TreeSetDemo4.Person cannot be cast to java.base/java.lang.Comparable
    public class Person {
        private String name;
        private int age;
    
        public Person(){}
        public Person(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 "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
        @Test
        public void fun1(){
            //1.按照年龄来排序
            TreeSet<Person>ts=new TreeSet<>();
            ts.add(new Person("张三",23));
            ts.add(new Person("张三",23));
            ts.add(new Person("张三",23));
            ts.add(new Person("李四",24));
            ts.add(new Person("王五",24));
            System.out.println("ts = " + ts);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    unity局部坐标和世界坐标角度介绍
    ARFoundation系列讲解 - 70 HumanBodyTracking3D
    【软考】5.1 七层模型/局域网/TCP-IP协议
    Zabbix 使用同一ODBC监控不同版本MySQL
    MySQL导入导出、视图、索引、执行计划
    魔法导航菜单
    Linux C select 的学习
    ModelScope-agent体验
    搜索引擎之ElasticSearch(es)入门学习、ELK 和 beats
    通过全流量查看部门或客户端网络使用情况
  • 原文地址:https://blog.csdn.net/TZ845195485/article/details/126083013