☞ java容器都有哪些?
常用容器:
☞ Collection和Collections有什么区别?
- java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。
- Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
☞ List、Set、Map之间的区别是什么?
项 | List | Set | Map |
---|---|---|---|
继承接口 | Collection | Collection | |
实现类 | AbstractList(ArrayList,Vector,LinkedList) | AbstractSet(HashSet,LinkedHashSet,TreeSet) | HashMap,HashTable |
常用方法 | add(),remove(),clear(),get(),contains(),size() | add(),remove(),clear(),contains(),size() | get(),put(),remove(),clear(),containsKey(),cotainsValue(),size(),keySet(),values() |
是否有序 | 有序 | 无序(实际上由hashCode决定) | |
元素重复性 | 可重复 | 不可重复 | 不可重复 |
线程安全 | Vector线程安全 | HashTable线程安全 |
☞ HashMap和Hashtable有什么区别?
- HashMap没有HashTable的contains()方法,有containsKey()和containsValue()方法
- HashMap线程不安全,HashTable线程安全;HashMap效率比HashTable高
- HashMap允许键值为空;HashTable不允许
- HashTable的线程安全是通过synchronized实现的
多线程下使用HashMap,如何保证线程安全?
使用Collections.synchronizedMap(m)获取一个被装饰过的map,该map的所有方法被重写,均加了synchronized修饰,源码示例如下
private static class SynchronizedMap<K, V> implements Map<K, V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L;
private final Map<K, V> m; // Backing Map
final Object mutex; // Object on which to synchronize
SynchronizedMap(Map<K, V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
}
SynchronizedMap(Map<K, V> m, Object mutex) {
this.m = m;
this.mutex = mutex;
}
public int size() {
synchronized (mutex) {
return m.size();
}
}
public boolean isEmpty() {
synchronized (mutex) {
return m.isEmpty();
}
}
...
}
SynchronizedMap是Collections的内部类,实现了Map接口,故此处使用的装饰者模式(即静态代理)
☞ 如何决定使用HashMap还是TreeMap?
如果只是对元素进行插入,删除,定位元素这类操作,HashMap是最好的选择;如果需要给元素排序,就是用TreeMap
☞ 说一下HashMap的实现原理?
Java中数组查询快增删慢,链表增删快但是查询慢;hashmap结合数组和链表的优点,使得查询和增删都非常快,时间复杂度平均为O(1);hashmap底层是一个可以扩展的entry数组,用于存储键值对;在添加元素时,hashmap会重新计算key的hash值,从而得到元素在entry数组中的下标;如果数组在该位置已经存在元素了,则该位置的元素以链表的形式存在,新增加的元素放置在链表的首部;在jdk1.8中,如果链表中的节点超过8个后,链表会转化为红黑树,以提高查询效率,时间复杂度平均由O(n)降低至O(log(n))
☞ 说一下HashSet的实现原理?
- HashSet底层由HashMap实现
- HashSet的值存放于HashMap的key上
- HashSet无序,允许null值存入,非线程安全
☞ ArrayList和LinkedList的区别是什么?
- 两者都是线程不安全的容器
- ArrayList底层使用数组,LinkedList底层是双向循环链表
//存储ArrayList元素的数组缓冲区
private transient Object[] elementData;
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
- ArrayList支持随机访问,linkedList不支持随机访问
- 使用下标访问元素,ArrayList时间复杂度是O(1),LinkedList是O(n)
- 添加或删除元素时,ArrayList时间复杂度为O(n),LinkedList是O(1)
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
☞ 如何实现数组和List之间的转换?
数组转换成List(转换之后只能进行访问不能进行删除或者添加元素)(转换之后为什么不增删元素?)
arr.asList();
List转换成数组
list.toArray();
☞ ArrayList和Vector的区别是什么?
ArrayList和Vector都是基于数组的实现,ArrayList非线程安全,Vector线程安全
☞ Array和ArrayList有何区别?
- Array可以容纳基本类型和对象,ArrayList只能容纳对象
- Array容量固定,ArrayList容量可以变化
☞ 在Queue中poll()和remove()有什么区别?
poll()和remove()都是取出并删除队首的元素,区别是队列为空时,poll()返回null,而remove抛出异常
☞ 哪些集合类是线程安全的?
- vector,向量:线程安全的数组
- Stack,栈:一个线程安全的容器,继承了vector,线程安全,特点是先进后出
- HashTable:一个线程安全的map
☞ 迭代器Iterator?
- 迭代器Iterator是一种设计模式
- 迭代器Iterator用于遍历容器中的元素
- 迭代器Iterator本身是一个接口,提供了三个方法:
boolean hasNext();
E next();
void remove();
但是具体的需要容器去实现,如hashmap:
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
☞ Iterator怎么使用?有什么特点?
Iterator本身提供了三个核心方法:
//判断是否存在下一个元素
boolean hasNext();
//取出下一个元素
E next();
//移除当前元素
void remove();
特点:单向移动,功能简单
☞ Iterator和ListIterator有什么区别?
- Iterator可用来遍历Set和List集合,ListIterator只能用来遍历List
- Iterator可以前向遍历,ListIterator既可以前向遍历也可以后向遍历
- ListIterator继承于Iterator
☞ 怎么确保一个集合不能被修改?
Collections包下的unmodifiableMap方法,装饰传入的map,当调用任何修改方法时,会抛出UnsupportedOperationException异常
Map<String, Object> map = new HashMap<>();
map.put("name", "lizza");
map.put("age", 18);
System.out.println(map);
map = Collections.unmodifiableMap(map);
map.put("name", "john");
System.out.println(map);