---------------java基础-----------------
你都知道哪些常用的Map集合?
- HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1) - HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize*2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length - ConcurrentHashMap
底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是
volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
HashMap的get过程
①、调用 hash(K) 方法(计算 K 的 hash 值)从而获取该键值所在链表的数组下标;②、顺序遍历链表,equals()方法查找相同 Node 链表中 K 值对应的 V 值
HashMap的put过程
①、调用 hash(K) 方法计算 K 的 hash 值,然后结合数组长度,计算得数组下标;②、调整数组大小(当容器中的元素个数大于 capacity * loadfactor 时,容器会进行扩容resize 为 2n);
③、i.如果 K 的 hash 值在 HashMap 中不存在,则执行插入,若存在,则发生碰撞;
ii.如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 true,则更新键值对;
iii. 如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 false,则插入链表的尾部(尾插法)或者红黑树中(树的添加方式)
HashMap初始化容量、扩容机制
默认大小为16。初始化容量是比传入容量参数值大的最小的2的n次方,比如传入6,实际分配8。
当hashmap中的元素个数超过数组大小*loadFactor(默认值为0.75)时就会把数组的大小扩展为原来的两倍大小,然后重新计算每个元素在数组中的位置
怎么按添加顺序存储元素
按添加顺序使用LinkedHashMap,
按自然顺序使用TreeMap,
自定义排序TreeMap(Comparetor c)
HashMap 的遍历方
- for-each map.keySet() – 只需要K值的时候,推荐使用 for (String key :
map.keySet()) {
map.get(key); } - for-each map.entrySet() – 当需要V值的时候,推荐使用 for (Map.Entry<String,
String> entry : map.entrySet()) {
entry.getKey();
entry.getValue(); } - for-each map.entrySet().iterator() Iterator<Map.Entry<String,
String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
entry.getKey();
entry.getValue(); }
List
List,Set都是继承自Collection接口。都是用来存储一组相同类型的元素的。
List特点:元素有放入顺序,元素可重复 。有顺序,即先放入的元素排在前面。
Set特点:元素无放入顺序,元素不可重复。无顺序,即先放入的元素不一定排在前面。不可重复,相同元素在set中只会保留一份。所以,有些场景下,set可以用来去重。
List主要有ArrayList、LinkedList与Vector几种实现
ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步
LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快)
Vector:底层是数组数据结构 线程同步(数组长度是可变的百分之百延长)(无论查询还是增删都很慢,被ArrayList替代了)。其他要实现线程安全使用工具类Collections.synchronizedList(new ArrayList())方法
Array.asList获得的List有何特点
- asList 得到的只是一个 Arrays 的内部类,一个原来数组的视图 List,因此如果对它进行增删操作会报错
- 用 ArrayList 的构造器可以将其转变成真正的 ArrayList
Set
Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set具有与Collection完全一样的接口,实际上Set就是Collection,只 是行为不同。
Set接口主要实现了两个实现类
HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。
“==” 和 equals()的区别
基本数据类型比较的是值;
引用类型比较的是地址值。