JAVA 集合概览
Map 接口
HashMap和Hashtable区别:
-
线程是否安全: HashMap是非线程安全的,HashTable是线程安全的,因为HashTable内部的方法基本都经过synchronize修饰.如果保证线程安全建议使用ConcurrentHashMap
-
效率: 因为线程安全的问题,HashMap要比HashTable效率高一点.另外HashTable基本淘汰,强烈不建议在代码中使用
-
对Null Key 和 Null Value的支持: HashMap可以存储null的key和value,但null作为key只能出现一个,null可以作为多个值;HashTable不允许有null键和null值,否则会抛出 NPE(NullPointerException)
-
初始容量大小和每次扩容量大小的不同:
-
创建时如果不指定初始容量,HashTable默认的初始大小为11,之后每次扩容,容量变为原来的2n+1;
HasHMap默认的初始值大小为16.之后每次扩容,容量变为原来的2倍数
-
创建时如果给定了容量的初始值,那么HashTable会直接使用你==给定的大小==
HashMap会将其扩充为==2的幂次方大小== HashMap中的tableSizeFor()方法保证.
总结: HashMap总是使用2的幂作为哈希表的大小
-
-
底层数据结构:
- JDK1.8以后的HashMap在解决哈希冲突时有了较大的变化,当链表长度大于==阈值(默认值)== 将链表转换红黑树前会判断,如果当前数组的长度小于64,那么会选择先进行数组扩容,而不是转换为红黑树 将链表转化为红黑树,以减少搜索时间
- Hashtable没用这样的机制
-
HashMap 中带有初始容量的构造函数:
/** 构造一个具有指定初始容量和负载因子的空HashMap 。 参数: initialCapacity –初始容量 loadFactor –负载系数 抛出: IllegalArgumentException如果初始容量为负或负载系数为正 推断的注释: @ org.jetbrains.annotations.Contract(pure = true) */ public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity); } -
如何保证扩容时2的幂次方
/** * Returns a power of two size for the given target capacity. * 对于给定的目标容量,返回两倍大小的幂。 */ static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }
HashMap和HashSet的区别:
HashSet底层是基于HashMap实现的.
HashSet的源码非常少,因为除了==clone(),writerObject(),readObject()==是HashSet自己实现外.其它都是调用HashMap中的方法
HashMap HashSet 实现了Map接口 实现了Set接口 存储键值对 仅存储对象 调用put()先map中添加元素 调用add()向Set中添加元素 HashMap使用键(key)计算HashCode HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,就要使用equals()方法用来判断对象的相等性
HashMap和TreeMap区别:
- TreeMap和HashMap都继承了AbstractMap,但是需要注意的是TreeMap还实现了NacigableMap接口和SortedMap接口
-
实现了NacigableMap接口让TreeMap有了对集合内元素的==搜索的能力==
-
实现SortedMap接口让TreeMap有了对集合中的元素根据键排序的能力.默认是按照key的升序排序,不过也可以指定排序的比较器
import java.util.Comparator; import java.util.TreeMap; /** * 类名称:Demo <br> * 类描述:TODO <br> * * @author 张兆发 * @version 1.0.0 * @date 创建时间:2021/2/22 7:54 下午 <br> */ public class Demo { private Integer age; public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Demo(Integer age) { this.age = age; } public static void main(String[] args) { //方式一 TreeMap<Demo,String> treeMap = new TreeMap<>(new Comparator<Demo>() { @Override public int compare(Demo o1, Demo o2) { if(o1.getAge()> o2.getAge()){ return 1; } if(o1.getAge()< o2.getAge()){ return -1; } return 0; } }); //方式二 TreeMap<Demo, String> treeMap = new TreeMap<>((Demo1, Demo2) > { int num = Demo1.getAge() - Demo2.getAge(); return Integer.compare(num, 0); }); treeMap.put(new Demo(19),"demo1"); treeMap.put(new Demo(141),"demo2"); treeMap.put(new Demo(11),"demo3"); treeMap.put(new Demo(3),"demo4"); treeMap.put(new Demo(321),"demo5"); treeMap.put(new Demo(1112),"demo6"); treeMap.entrySet().stream().forEach( data -> { System.out.println(data.getValue()); } ); } } -
综上,相比于 HashMap 来说 TreeMap 主要多了对集合中的元素根据键排序的能力以及对集合内元素 的搜索的能力。
HashSet如何检查重复:
- 当把对象加入HashSet时,HashSet会先计算对象的HashCode值判断对象加入的位置,同时也会与其它加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现,但是如果发现有相同的hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同,如果相同HashSet就不会让加入操作成功
- hashCode()与equals()的规定
- 如果两个对象相等,则hashcode一定也相同
- 两个对象相等,对两个equals方法返回true
- 两个对象有相同的hashcode值,他们也不一定是相等的
- equals方法被覆盖过,则hashcode方法也必须被覆盖过