ArrayList 和 Vector 的区别
Vector 和 ArrayList 的实现几乎是一样的,区别在于:
1)最重要的区别: Vector 在方法上使用了 synchronized 来保证线程安全,同时由于这个原因,在性能上 ArrayList 会有更好的表现。
2) Vector 扩容后容量默认变为原来 2 倍,而 ArrayList 为原来的 1.5 倍。
有类似关系的还有:StringBuilder 和 StringBuffer、HashMap 和 Hashtable。
ArrayList 和 LinkedList 的区别
- ArrayList 底层基于动态数组实现,LinkedList 底层基于双向链表实现。
- 对于随机访问(按 index 访问,get/set 方法):ArrayList 通过 index 直接定位到数组对应位置的节点,而 LinkedList 需要从头结点或尾节点开始遍历,直到寻找到目标节点,因此在效率上 ArrayList 优于 LinkedList。
- 对于随机插入和删除:ArrayList 需要移动目标节点后面的节点(使用 System.arraycopy 方法移动节点),而 LinkedList 只需修改目标节点前后节点的 next 或 prev 属性即可,因此在效率上 LinkedList 优于 ArrayList。
- 对于顺序插入和删除:由于 ArrayList 不需要移动节点,因此在效率上比 LinkedList 更好。这也是为什么在实际使用中 ArrayList 更多,因为大部分情况下我们的使用都是顺序插入。
- 两者都不是线程安全的。
- 内存空间占用: ArrayList 的空间花费主要体现在,list 列表的结尾会预留一定的容量空间。而 LinkedList 的空间花费体现在,它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)
HashSet 是如何保证不重复的
HashSet 底层使用 HashMap 来实现,见下面的源码,元素放在 HashMap 的 key 里,value 为固定的 Object 对象。当 add 时调用 HashMap 的 put 方法,如果元素不存在,则返回 null 表示 add 成功,否则 add 失败。
由于 HashMap 的 key 值本身就不允许重复,HashSet 正好利用 HashMap 中 key 不重复的特性来校验重复元素。
// 被 transient 修饰的成员变量不参与序列化过程
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
TreeSet 清楚吗?能详细说下吗?
TreeSet 底层默认使用 TreeMap 来实现。而 TreeMap 通过实现 Comparator(或 Key 实现 Comparable)来实现自定义顺序。
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
public TreeSet() {
this(new TreeMap<E,Object>());
}
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
Comparable 和 Comparator 比较
- Comparable 是排序接口,一个类实现了 Comparable 接口,意味着“该类支持排序”。Comparator 是比较器,我们可以实现该接口,自定义比较算法,创建一个 “该类的比较器” 来进行排序。
- Comparable 相当于“内部比较器”,而 Comparator 相当于“外部比较器”。
- Comparable 的耦合性更强,Comparator 的灵活性和扩展性更优。
- Comparable 可以用作类的默认排序方法,而 Comparator 则用于默认排序不满足时,提供自定义排序。
耦合性和扩展性的问题,举个简单的例子:
当实现类实现了 Comparable 接口,但是已有的 compareTo 方法的比较算法不满足当前需求,此时如果想对两个类进行比较,有两种办法:
- 修改实现类的源代码,修改 compareTo 方法,但是这明显不是一个好方案,因为这个实现类的默认比较算法可能已经在其他地方使用了,此时如果修改可能会造成影响,所以一般不会这么做。
- 实现 Comparator 接口,自定义一个比较器,该方案会更优,自定义的比较器只用于当前逻辑,其他已有的逻辑不受影响。
介绍下 CopyOnWriteArrayList
CopyOnWriteArrayList 是 ArrayList 的线程安全版本,也是 copy-on-write(COW,写时复制)的一种实现。
在读操作时不加锁,跟 ArrayList 类似;在写操作时,复制出一个新的数组,在新数组上进行操作,操作完了,将底层数组指针指向新数组。适合使用在读多写少的场景。
例如 add(E e) 方法的操作流程如下:使用 ReentrantLock 加锁,拿到原数组的 length,使用 Arrays.copyOf 方法从原数组复制一个新的数组(length+1),将要添加的元素放到新数组的下标 length 位置,最后将底层数组指针指向新数组。
List、Set、Map 三者的区别
-
List(对付顺序的好帮手): 存储的对象是可重复的、有序的。
-
Set(注重独一无二的性质):存储的对象是不可重复的、无序的。
-
Map(用 Key 来搜索的专业户): 存储键值对(key-value),不能包含重复的键(key),每个键只能映射到一个值。
Map、List、Set 有哪些线程安全类和线程不安全的类
Map
-
线程安全:CocurrentHashMap、Hashtable
-
线程不安全:HashMap、LinkedHashMap、TreeMap、WeakHashMap
List
-
线程安全:Vector(线程安全版的 ArrayList)、Stack(继承 Vector,增加 pop、push 方法)、CopyOnWriteArrayList
-
线程不安全:ArrayList、LinkedList
Set
-
线程安全:CopyOnWriteArraySet(底层使用 CopyOnWriteArrayList,通过在插入前判断是否存在实现 Set 不重复的效果)
-
线程不安全:HashSet(基于 HashMap)、LinkedHashSet(基于 LinkedHashMap)、TreeSet(基于 TreeMap)、EnumSet
Collection 与 Collections 的区别
-
Collection:集合类的一个顶级接口,提供了对集合对象进行基本操作的通用接口方法。Collection 接口的意义是为各种具体的集合提供了最大化的统一操作方式,常见的 List 与 Set 就是直接继承 Collection 接口。
-
Collections:集合类的一个工具类/帮助类,提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
参考链接