☞ 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);