• 集合框架整理


    集合框架可以分为两个部分:Collection和Map,详细的框架图如下:

    我们先来分析一下Collection集合框架,Collection包括两大体系List和Set,其中List中的元素存取有序、元素可重复、有索引,可以根据索引获取值,Set的元素存取无序、不能存储重复元素。

    List下面有有三个实现类ArrayList、vector、LinkedList,ArrayList和Vector底层是数组,LinkedList底层实现是链表。

    ArrayList和Vector底层是数组实现,能够根据索引直接获取值,所以查找快,但是删除和添加操作慢,因为需要向前或向后挪动多个元素。Vector是旧版本的,线程安全,所以如果是单线程进行存取,最好用ArrayList,效率快,如果是多线程我们最好用Vector来进行存储,因为Vector里面的方法是线程安全的。

    LinkedList是基于链表实现的,查找必须从头开始,所以查找速度慢,但是删除和添加只需要挪动两个节点,所以删除和添加速度快。链表提供了特殊的方法,所以链表可以实现栈或者队列。

    Set接口有三个实现类HashSet、LinkedHashSet、TreeSet

    HashSet集合存储不重复,无序,原理是什么?因为HashSet底层实现是哈希表,哈希表通过hashCode()和equals()方法来共同保证元素不重复。首先根据存储的元素算出hashCode值,然后根据算出的hashCode值和数组的长度算出存储的下标;如果下标位置无元素,那么直接存储,如果有元素,那么就要使用存入的元素和已经存在的元素进行equals方法进行比较,如果结果为真就不存储,如果为假就进行存储,以链表方式进行存储。

    注意:一般我们自定义的类都需要重新写hashCode()和equals(),必须要重写Object类的这两个方法,因为hash值是根据存储的元素获得的

    如:

    @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;
        Person other = (Person) 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;
    }

    LinkedHashSet基于链表和哈希表实现的,所以具有存取有序,元素唯一的特点。

    package cn.yqg.day4;
    
    public class Person {
      private int age ;
      private String name;
      public Person(int age,String name) {
          this.age=age;
          this.name=name;
      }
      
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
    
    @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;
        Person other = (Person) 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;
    }
    }
    package cn.yqg.day4;
    
    
    import java.util.Iterator;
    import java.util.LinkedHashSet;
    
    public class Test {
        public static void main(String[] args) {
            LinkedHashSet<Person> list=new LinkedHashSet<>();
            list.add(new Person(1,"12"));
            list.add(new Person(1,"12"));
            list.add(new Person(3,"14"));
            list.add(new Person(4,"15"));
            
            Iterator<Person> it=list.iterator();
            while(it.hasNext()) {
                Person p=it.next();
                System.out.println(p);
            }
        }
    }

    运行结果:

    Person [age=1, name=12]
    Person [age=3, name=14]
    Person [age=4, name=15]

    TreeSet:特点存取无序,元素唯一,可以进行排序;TreeSet是基于二叉树实现。

    存储过程:如果是第一个元素,直接存入,作为根节点,下一个元素进来就会进行比较,如果大于加点就放在节点右边,如果小于节点就放在节点左边,等于节点就不存储,后面的元素会依次进行比较直到有存储的位置为止。

    package cn.yqg.day4;
    
    import java.util.TreeSet;
    
    public class Test2 {
        public static void main(String[] args) {
            TreeSet<String> set=new TreeSet<>();
            set.add("abd");
            set.add("abc");
            set.add("bcd");
            set.add("bce");
            set.add("bce");
            
            for(String str : set) {
                System.out.println(str);
            }
        }
    }

    运行结果:

    abc
    abd
    bcd
    bce

    TreeSet保证元素唯一有两种方式:

    1.自定义对象实现Comparable()接口,重写CompareTo()方法,该方法返回0表示相等,大于0表示存入的元素比被比较的元素大。反之小于0。

    2.在创建TreeSet的时候向构造器中传入比较器Comparator接口实现类的对象,实现Comparator接口重写compare方法。

    如果向TreeSet中存储自定义类没实现Comparable接口,或者没有传入Comparator比较器时,会出现ClassCastException异常。

    下面演示用两种方式存储自定义对象

    package cn.yqg.day4;
    
    import java.util.TreeSet;
    
    public class Test4 {
       public static void main(String[] args) {
         TreeSet<Person> treeSet=new TreeSet<>();
         treeSet.add(new Person(4,"1"));
         treeSet.add(new Person(1,"张三"));
         treeSet.add(new Person(1,"李四"));
         treeSet.add(new Person(3,"大王"));
         treeSet.add(new Person(2,"小王"));
         treeSet.add(new Person(3,"大王"));
         treeSet.add(new Person(4,"1"));
         treeSet.add(new Person(4,"1"));
         
         for(Person p : treeSet) {
             System.out.println(p);
         }
    }
    }
    package cn.yqg.day4;
    
    public class Person implements Comparable<Person>{
      private int age ;
      private String name;
      public Person(int age,String name) {
          this.age=age;
          this.name=name;
      }
      
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
    
    @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;
        Person other = (Person) 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;
    }
    
    @Override
    public int compareTo(Person o) {
        int rusult=this.age-o.age;
        if(rusult==0) {
            return this.name.compareTo(o.name);
        }
        return rusult;
    }
    
    }

    另一种方式:使用比较器Comparator

    package cn.yqg.day4;
    
    import java.util.Comparator;
    import java.util.TreeSet;
    
    public class Test5 {
       public static void main(String[] args) {
        TreeSet<Person2> treeSet2=new TreeSet<>(new Comparator<Person2>() {
    
            @Override
            public int compare(Person2 o1, Person2 o2) {
                if(o1==o2) {
                    return 0;
                }
                int result=o1.getAge()-o2.getAge();
                if(result==0) {
                    return o1.getName().compareTo(o2.getName());
                }
                return result;
            }
            
        });
        treeSet2.add(new Person2(1,"张三"));
        treeSet2.add(new Person2(5,"小龙"));
        treeSet2.add(new Person2(4,"3"));
        treeSet2.add(new Person2(5,"小庆"));
        treeSet2.add(new Person2(4,"1"));
        treeSet2.add(new Person2(1,"1"));
        
        for(Person2 p : treeSet2) {
            System.out.println(p);
        }
      }
    }
    package cn.yqg.day4;
    
    public class Person2 {
        private int age ;
          private String name;
          public Person2(int age,String name) {
              this.age=age;
              this.name=name;
          }
          
        @Override
        public String toString() {
            return "Person [age=" + age + ", name=" + name + "]";
        }
    
        
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }

    运行结果:

    Person [age=1, name=1]
    Person [age=1, name=张三]
    Person [age=4, name=1]
    Person [age=4, name=3]
    Person [age=5, name=小庆]
    Person [age=5, name=小龙]

    -------------------------------------------------------------------------------------------------------------------

    Collection体系总结:

    List:“特点”,存取有序,可存重复值,元素有索引。

    ArrayList:数组结构,查询速度快,增删慢,线程不安全,效率高。

    Vector:数组结构,查询快,增删慢,线程安全,效率低。

    LinkedList:链表结构,增删快,查询慢,线程不安全,效率高。

    Set:“特点”,存取无序,不可存重复值,无索引。

    HashSet:哈希表,存储无序,元素不重复,无索引。

    LinkedHashSet:链表加哈希表,存储有序,无索引,值不重复。

    TreeSet:二叉树,元素不重复,存取无序,但是可以进行排序。

    两种排序方式:

    1.自然排序:我们的元素必须实现Comparable接口,实现CompareTo()方法。

    2.比较器排序:我们自定义的类实现Comparator接口,比较器实现Compare方法。然后创建TreeSet的时候把比较器对象当做参数传递给TreeSet。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    现在我们来看看Map集合框架

    Map是一个双列集合,保存的是键值对,键要求保持唯一性,值可以重复。键值一一对应。Map存储是将键值传入Entry,然后存储Entry对象。

    Map接口实现类有三个,分别为HashMap、TreeMap、LinkedHashMap。

    HashMap:是基于hash表实现的,所以存储自定义对象作为键时,必须重写hashCode和equals方法。存取无序

    package cn.yqg.day4;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map.Entry;
    import java.util.Set;
    
    public class Test6 {
       public static void main(String[] args) {
        HashMap<Person,String> map=new HashMap<Person,String>();
        map.put(new Person(1,"pp"),"java");
        map.put(new Person(2,"kk"),"c");
        map.put(new Person(1,"pp"),"c++");
        map.put(new Person(3,"ll"),"java");
        
        Set<Entry<Person,String>> entrySet=map.entrySet();
        Iterator<Entry<Person,String>> it=entrySet.iterator();
        while(it.hasNext()) {
            Entry<Person,String> entry=it.next();
            System.out.println(entry.getKey()+"-----"+entry.getValue());
        }
    }
    }

    结果:

    Person [age=1, name=pp]-----c++
    Person [age=3, name=ll]-----java
    Person [age=2, name=kk]-----c

    我们发现如果键重复,后面的值会覆盖前面的值。存取无序。

    LinkedHashMap:用法基本和HashMap一致,基于链表和哈希表来实现的,所以有存取有序,键不重复的特点。

    package cn.yqg.day4;
    
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map.Entry;
    
    public class Test7 {
             public static void main(String[] args) {
             LinkedHashMap<Person,String> map=new LinkedHashMap<Person,String>();
                map.put(new Person(1,"pp"),"java");
                map.put(new Person(2,"kk"),"c");
                 map.put(new Person(1,"pp"),"c++");
                 map.put(new Person(1,"pp"),"R");
                 for(Entry<Person,String> entry : map.entrySet()) {
                     System.out.println(entry.getKey()+"-----"+entry.getValue());
                 }
            }
    }

    实现结果:

    Person [age=1, name=pp]-----R
    Person [age=2, name=kk]-----c

    我们注意到键如果相同,值会被后面的覆盖掉。而且存取有序。

    TreeMap集合存储自定义对象,自定义对象始终作为TreeMap的key值,由于TreeMap底层实现是二叉树,所有存进去的数据都要进行排序,排序有两种方法,一种自定义类实现Comparable接口,实现CompareTo方法,另一种实现Comparator接口,实现自定义比较器Compare方法。

    package cn.yqg.day4;
    
    import java.util.Comparator;
    import java.util.TreeMap;
    import java.util.Map.Entry;
    
    public class Test8 {
        public static void main(String[] args) {
            TreeMap<Person,String> map=new TreeMap<>(new Comparator<Person>() {
    
                @Override
                public int compare(Person o1, Person o2) {
                    if(o1==o2) {
                        return 0;
                    }
                    int result=o1.getAge()-o2.getAge();
                    if(result==0) {
                        result=o1.getName().compareTo(o2.getName());
                    }
                    return result;
                }
                
            });
            
            map.put(new Person(1,"pp"),"java");
              map.put(new Person(2,"kk"),"c");
               map.put(new Person(6,"pp"),"c++");
               map.put(new Person(0,"pp"),"R");
            map.put(new Person(-7,"pp"),"jsp");
            map.put(new Person(0,"pp"),"js");
            for(Entry<Person,String> entry : map.entrySet()) {
                 System.out.println(entry.getKey()+"-----"+entry.getValue());
             }
        }
    }
    运行结果:
    Person [age=-7, name=pp]-----jsp Person [age=0, name=pp]-----js Person [age=1, name=pp]-----java Person [age=2, name=kk]-----c Person [age=6, name=pp]-----c++
  • 相关阅读:
    uni-app拒绝授权后再次授权
    vue触底操作
    vue滚动条滚到到底部触发的方法
    pagination插件使用例子
    修改后台返回数据的字段
    v-cloak指令的作用
    修改checkbox样式
    获取selected的值
    前端工程师必备的几个实用网站
    html发展史简介(摘抄)
  • 原文地址:https://www.cnblogs.com/yanqingguo/p/9817039.html
Copyright © 2020-2023  润新知