java基础---集合(2)
一、 Set 集合
- java.util.Set集合是Collection集合的子集合,与List集合平级。该集合中元素没有先后放入次序,且不允许重复。
- 存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的
- 保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个
- 该集合的主要实现类是:HashSet类 和 TreeSet类以及LinkedHashSet类。
- HashSet类的底层是采用哈希表进行数据管理的,数组+链表
- TreeSet类的底层是采用红黑树进行数据管理的
- LinkedHashSet类与HashSet类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
- Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法
1. HashSet
- 底层是采用哈希表进行数据管理的,数组+链表,数组初始容量为16, 当如果使用率超过0.75,就会扩大容量为原来的2倍;不能保证元素的排列顺序,非线程安全,集合元素可以为null
- 为什么用Eclipse/IDEA复写hashCode方法,有31这个数字?
- 选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
- 31只占用5bits,相乘造成数据溢出的概率较小。
- 31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化。 (提高算法效率)
- 31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除! (减少冲突)
- 添加元素的过程
- 我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素
-
如果此位置上没有其他元素,则元素a添加成功。 --->情况1
-
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
-
如果hash值不相同,则元素a添加成功。--->情况2
-
如果hash值相同,进而需要调用元素a所在类的equals()方法:equals()返回true,元素a添加失败;equals()返回false,则元素a添加成功。--->情况2
-
-
对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。
-
jdk 7 :元素a放到数组中,指向原来的元素。
-
jdk 8 :原来的元素在数组中,指向元素a
-
2. LinkedHashSet
- 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的
- LinkedHashSet 不允许集合元素重复
- 向Set添加的数据,其所在的类一定要重写hashCode()和equals(),相等的对象必须具有相等的散列码;对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
3. TreeSet
- 底层采用红黑树进行数据的管理,当有新元素插入到TreeSet集合时,需要使用新元素与集合中已有的元素依次比较来确定新元素的合理位置
- 比较元素大小的规则有两种方式:
- 使用元素的自然排序规则进行比较并排序,让元素类型实现java.lang.Comparable接口;
- BigDecimal、 BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
- Character:按字符的 unicode值来进行比较
- Boolean: true 对应的包装类实例大于 false 对应的包装类实例
- String:按字符串中字符的 unicode 值进行比较
- Date、 Time:后边的时间、日期比前面的时间、日期大
- 使用比较器规则进行比较并排序,构造TreeSet集合时传入java.util.Comparator接口;
- 自然排序的规则比较单一,而比较器的规则比较多元化,而且比较器优先于自然排序;
- 使用元素的自然排序规则进行比较并排序,让元素类型实现java.lang.Comparable接口;
@Test public void tes1(){ HashSet set = new HashSet(); Person p1 = new Person(1001,"AA"); Person p2 = new Person(1002,"BB"); set.add(p1); set.add(p2); p1.name = "CC"; set.remove(p1); //找不到new Person(1001,"AA"); System.out.println(set);//[Person{name='CC', id=1001}, Person{name='BB', id=1002}] set.add(new Person(1001,"CC")); System.out.println(set);//[Person{name='CC', id=1001}, Person{name='CC', id=1001}, Person{name='BB', id=1002}] set.add(new Person(1001,"AA")); System.out.println(set);//[Person{name='CC', id=1001}, Person{name='CC', id=1001}, Person{name='AA', id=1001}, Person{name='BB', id=1002}] } class Person{ public String name; public int id; public Person(int id,String name) { this.name = name; this.id = id; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", id=" + id + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; if (id != person.id) return false; return name != null ? name.equals(person.name) : person.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + id; return result; } }
二、Map集合
- java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
- K - 此映射所维护的键(Key)的类型,相当于目录。
- V - 映射值(Value)的类型,相当于内容。该集合中key是不允许重复的,而且一个key只能对应一个value。
- 该集合的主要实现类有:HashMap类、TreeMap类、LinkedHashMap类、Hashtable类、Properties类。
- HashMap类的底层是采用哈希表进行数据管理的。
- TreeMap类的底层是采用红黑树进行数据管理的。
- LinkedHashMap类与HashMap类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
- Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作为key或者value的数值。
- Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的。
- Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能。经常用于根据key检索value的业务场景。
| 方法声明 | 功能介绍 |
| V put(K key, V value) | 将Key-Value对存入Map,若集合中已经包含该Key,则替换该Key所对应的Value,返回值为该Key原来所对应的Value,若没有则返回null |
| V get(Object key) | 返回与参数Key所对应的Value对象,如果不存在则返回null |
| boolean containsKey(Object key); | 判断集合中是否包含指定的Key |
| boolean containsValue (Object value); | 判断集合中是否包含指定的Value |
| V remove(Object key) | 根据参数指定的key进行删除 |
| Set keySet() | 返回此映射中包含的键的Set视图 |
| Collection values() | 返回此映射中包含的值的Set视图 |
| Set<Map.Entry<K,V>> entrySet() | 返回此映射中包含的映射的Set视图 |
- 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。若该位置没有元素,则将该键值对直接放入即可。
- 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
- 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较。
- 若相等则将对应的value修改,否则将键值对直接放入即可
- DEFAULT_INITIAL_CAPACITY : HashMap的默认容量是16。
- DEFAULT_LOAD_FACTOR:HashMap的默认加载因子是0.75。
- threshold:扩容的临界值,该数值为:容量*填充因子,也就是12。
- TREEIFY_THRESHOLD:若Bucket中链表长度大于该默认值则转化为红黑树存储,该数值是8。
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,该数值是64
java.util.Collections类主要提供了对集合操作或者返回集合的静态方法。
| 方法声明 | 功能介绍 |
| static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) |
根据元素的自然顺序返回给定集 合的最大元素 |
| static T max(Collection<? extends T> coll, Comparator<? super T> comp) |
根据指定比较器引发的顺序返回 给定集合的最大元素 |
| static <T extends Object & Comparable<?super T>> T min(Collection<? extends T> coll) |
根据元素的自然顺序返回给定集 合的最小元素 |
| static T min(Collection<? extends T> coll, Comparator<? super T> comp) |
根据指定比较器引发的顺序返回 给定集合的最小元素 |
| static void copy(List<? super T> dest, List<? extends T> src) |
将一个列表中的所有元素复制到 另一个列表中 |
| 方法声明 | 功能介绍 |
| static void reverse(List<?> list) | 反转指定列表中元素的顺序 |
| static void shuffle(List<?> list) | 使用默认的随机源随机置换指定的列表 |
| static <T extends Comparable<? super T>> void sort(List list) |
根据其元素的自然顺序将指定列表按升 序排序 |
| static void sort(List list, Comparator<? super T> c) | 根据指定比较器指定的顺序对指定列表 进行排序 |
| static void swap(List<?> list, int i, int j) | 交换指定列表中指定位置的元素 |
浙公网安备 33010602011771号