List、Set接口是继承collection父接口的,
List它是按照对象的进入顺序进行保存的,因此,它可以能对列表中的每个元素进行存入和删除的位置,能够精确地控制。list保存的数据是可以重复的,list的子类有LinkedList、Vrctor和ArrayList集合。
总结:List是一种有序(存储顺序)可重复(元素)的集合。
Set接口也是和List一样继承Collection接口。Set在数学上的意义就是集合的概念,他和List不一样的是,不允许集合中的元素重复。所以存入的元素都必须定义equals()方法来确保对象的唯一性,Set接口有两个实现来Hashset和TreeSet,其中TreeSet是实现了SortedSet接口的。
总结:Set是一种无序(存储顺序)不可重复(元素)的集合。
Map集合它提供了一个键映射到值的一个数据结构,记住map的值是个重复,但键是唯一的,Map的子类有很多比如创建的是HashMap和LinkedHashMap。
总结:Map是一种以键值对形式存储的集合。
List:ArrayList,LinkedList,Vector
1.ArrayList:是线程不安全的,效率高。
2.Vector:是线程安全的。
3.ArrayList和Vector都可以使用for语句或者迭代器遍历,但是Vector还可以使用枚举遍历。
LinkedList:采用双向循环链表实现。可以快速执行插入,删除的方法。线程不安全。
ArrayList:采用变长数组算法实现的,特点是:快,线程不安全。
Vector:采用变长数组算法实现的,特点是:慢,线程安全。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
Set区别对象是不是唯一的标准是,两个对象hashcode是不是一样,再判定两个对象是否equals;
Map 是先根据Key值的hashcode分配和获取对象保存数组下标的,然后再根据equals区分唯一值
所以对象需要重写父类(Object)的hashcode方法,Object的hashcode方法会根据两个对象的地址生成对相应的hashcode;
hashmap存储
存值规则:把Key的hashCode 与HashMap的容量 取余得出该Key存储在数组所在位置的下标(源码定位Key存储在数组的哪个位置是以hashCode & (HashMap容量-1)算法得出)
HashMap的扩容机制
我们向HashMap中存放一个元素(k1,v1),先根据k1的hashCode方法来决定在数组中存放的位置。
如果这个位置没有其它元素,将(k1,v1)直接放入Node类型的数组中,
这个数组初始化容量是16,默认的加载因子是0.75,也就是当元素加到12的时候,底层会进行扩容,扩容为原来的2倍。
Java8变成链表和红黑树的组合,数据少量存入的时候优先还是链表,当链表长度大于8,且总数据量大于64的时候,链表就会转化成红黑树,所以你会看到Java8的Hashmap的数据存储是数组+链表+红黑树的组合,如果数据量小于64则只有数组+链表,如果数据量大于64,且某一个数组下标数据量大于8,那么该处即为红黑树。
1.在put()方法中有调用addEntry()方法,这个方法里面是具体的存值,在存值之前还要判断是否需要扩容
2.调用扩容的方法resize()
3.扩容必须满足两个条件:
1、 存放新值的时候当前已有元素的个数必须大于等于阈值
2、 存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值)
4.transfer()在实际扩容时候把原来数组中的元素放入新的数组中
Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap
1.HashMap允许存null键和null值,HashTable不允许存null键和null值。
2.HashMap是线程不安全的,HashTable线程是安全的。
3.HashMap可以采用迭代器遍历集合中的元素,而HashTable既可以使用迭代器,还可以使用枚举遍历。
4.哈希表的作用是用来保证键的唯一性;
5.HashMap的实例有两个参数影响其性能:初试容量和加载因子,当哈希表中的条目数超出加载因子与当前容量的乘积时,要对哈希表进行rehash操作(即重建内部数据结构),容量扩大约为之前的两倍,加载因子默认值为0.75;
第一种:遍历HashMap的entrySet键值对集合
1.通过HashMap.entrySet()得到键值对集合;
2.通过迭代器Iterator遍历键值对集合得到key值和value值;
// 获取键值对的迭代器
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
key = (String) entry.getKey();
value = (String) entry.getValue();
System.out.println("key:" + key + "---" + "value:" + value);
}
第二种:遍历HashMap键的Set集合获取值;
1.通过HashMap.keySet()获得键的Set集合;
2.遍历键的Set集合获取值;
// 获取键集合的迭代器
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
key = (String) it.next();
value = (String) map.get(key);
System.out.println("key:" + key + "---" + "value:" + value);
}
第三种:遍历HashMap“值”的集合;
1.通过HashMap.values()得到“值”的集合
2.遍历“值”的集合;
// 获取值集合的迭代器
Iterator it = map.values().iterator();
while (it.hasNext()) {
value = (String) it.next();
System.out.println("value:" + value);
}
Set HashSet
HashMap相对于HashSet较快,hashset的底层是对HashMap的封装,他们计算value的方式都是一样的,HashSet的底层是HashMap,TreeSet的底层是TreeMap,
场景分析
-
如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
-
如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。
-
如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。
-
如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。