文章目录
- 1.整体类图
- 2.特点
- 1.Connection接口:
- 2.Map接口:
- 3.重点
- 1. HashMap与HashTable的区别?
- 2. Collections和Collection有什么区别?
- 3. HashMap详解
- 4. 为什么HashMap中String、Integer这样的包装类适合作为Key?
- ArrayList 和 Vector 的区别
- ArrayList和LinkedList的区别?
- Array 和 ArrayList 有什么区别?什么时候该应 Array 而不是 ArrayList 呢?
- HashSet是如何保证数据不可重复的?
- 参考文章
1.整体类图
简略版:
2.特点
1.Connection接口:
List 有序,可重复
- ArrayList
底层数据结构是数组,查询快,增删慢。
非线程安全 - LinkedList
底层数据结构是链表,查询慢,增删快。
非线程安全 - Vector(已过时)
底层数据结构是数组,查询快,增删慢。
线程安全 - Stack(已过时)
继承Vector,底层一般用list或deque实现,不用vector的原因应该是容量大小有限制,扩容耗时
线程安全
Set 无序,唯一
- HashSet
底层数据结构是哈希表。(无序)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals() - LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一 - TreeSet
底层数据结构是红黑树。(有序)
- 如何保证元素排序的呢?
自然排序
比较器排序 - 如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
2.Map接口:
- HashMap
无序,非线程安全 - TreeMap
有序,非线程安全 - Hashtable
无序,线程安全 - ConcurrentHashMap
有序,线程安全
3.重点
1. HashMap与HashTable的区别?
HashMap没有考虑同步,是线程不安全的;Hashtable使用了synchronized关键字,是线程安全的;
HashMap允许K/V都为null;后者K/V都不允许为null;
HashMap继承自AbstractMap类;而Hashtable继承自Dictionary类;
2. Collections和Collection有什么区别?
Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
它有两个常用的子接口,
List:对元素都有定义索引。有序的。可以重复元素。
Set:不可以重复元素。无序。
Collections是集合框架中的一个工具类。该类中的方法都是静态的
提供的方法中有可以对list集合进行排序,二分查找等方法。
通常常用的集合都是线程不安全的。因为要提高效率。
如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
3. HashMap详解
查看:HashMap详解
4. 为什么HashMap中String、Integer这样的包装类适合作为Key?
答:String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率
- 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况
- 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情况;
面试官:如果我想要让自己的Object作为K应该怎么办呢?
答:重写hashCode()和equals()方法
- 重写hashCode()是因为需要计算存储数据的存储位置,需要注意不要试图从散列码计算中排除掉一个对象的关键部分来提高性能,这样虽然能更快但可能会导致更多的Hash碰撞;
- 重写equals()方法,需要遵守自反性、对称性、传递性、一致性以及对于任何非null的引用值x,x.equals(null)必须返回false的这几个特性,目的是为了保证key在哈希表中的唯一性;
ArrayList 和 Vector 的区别
这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合,即存储在这两个集合中的元素位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引来取出某个元素,并且其中的数据是允许重复的,这是与 HashSet 之类的集合的最大不同处,HashSet 之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素。
ArrayList 与 Vector 的区别主要包括两个方面:
- 同步性:
Vector 是线程安全的,也就是说它的方法之间是线程同步(加了synchronized 关键字)的,而 ArrayList 是线程不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全的问题,所以效率会高一些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。 - 数据增长:
ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个人超过了容量时,就需要增加 ArrayList 和 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要去的一定的平衡。Vector 在数据满时(加载因子1)增长为原来的两倍(扩容增量:原容量的 2 倍),而 ArrayList 在数据量达到容量的一半时(加载因子 0.5)增长为原容量的 (0.5 倍 + 1) 个空间。
Vector类被认为已过时:
Vector中对每一个独立操作都实现了同步,这通常不是我们想要的做法。对单一操作实现同步通常不是线程安全的(举个例子,比如你想遍历一个Vector实例。你仍然需要申明一个锁来防止其他线程在同一时刻修改这个Vector实例。如果不添加锁的话,通常会在遍历实例的这个线程中导致一个ConcurrentModificationException)同时这个操作也是十分慢的(在创建了一个锁就已经足够的前提下,为什么还需要重复的创建锁)
当然,即使你不需要同步,Vector也是有锁的资源开销的。
总的来说,在大多数情况下,这种同步方法是存在很大缺陷的。正如Mr Brain Henk指出,你可以通过调用Collections.synchronizedList来装饰一个集合 -事实上 Vector 将“可变数组”的集合实现与“同步每一个方法”结合起来的做法是另一个糟糕的设计;
各个装饰方法能够更明确的指示其关注的功能实现。
对于Stack这个类-我更乐于使用Deque/ArrayDeque来实现
stackoverflow讨论地址
ArrayList和LinkedList的区别?
答:
- LinkedList 实现了 List 和 Deque 接口,一般称为双向链表;ArrayList 实现了 List 接口,动态数组;
- LinkedList 在插入和删除数据时效率更高,ArrayList 在查找某个 index 的数据时效率更高;
- LinkedList 比 ArrayList 需要更多的内存;
Array 和 ArrayList 有什么区别?什么时候该应 Array 而不是 ArrayList 呢?
答:
- Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。
- Array 大小是固定的,ArrayList 的大小是动态变化的。
- ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator() 等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
HashSet是如何保证数据不可重复的?
答:HashSet的底层其实就是HashMap,只不过我们HashSet是实现了Set接口并且把数据作为K值,而V值一直使用一个相同的虚值来保存,我们可以看到源码:
public boolean add(E e) {
// 调用HashMap的put方法,PRESENT是一个至始至终都相同的虚值
return map.put(e, PRESENT) == null;
}
由于HashMap的K值本身就不允许重复,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V,那么在HashSet中执行这一句话始终会返回一个false,导致插入失败,这样就保证了数据的不可重复性;
参考文章
https://www.jianshu.com/p/939b8a672070