一、ArrayList
數(shù)組集合應(yīng)用
// ArraysList 增刪慢 查詢快
// 根據(jù)源碼 無(wú)參構(gòu)造方法創(chuàng)建出來(lái)的是長(zhǎng)度為0的數(shù)組{}
List<Integer> list = new ArrayList<>();
// 此時(shí)add方法進(jìn)行源碼擴(kuò)容
list.add(100);
System.out.println(list.get(0));
add()方法擴(kuò)容源碼
public boolean add(E e) {
// 不需要關(guān)注
modCount++;
// e對(duì)象 elementData集合數(shù)組元素 size當(dāng)前數(shù)組長(zhǎng)度
add(e, elementData, size);
// 不管成功失敗 均返回true
return true;
}
private void add(E e, Object[] elementData, int s) {
// 滿足條件 進(jìn)入擴(kuò)容算法 不然就進(jìn)行正常賦值操作
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
// 至少需要加一個(gè)長(zhǎng)度
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 新長(zhǎng)度加上舊長(zhǎng)度的0.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// DEFAULT_CAPACITY 默認(rèn)長(zhǎng)度10
return Math.max(DEFAULT_CAPACITY, minCapacity);
// 超出最大二進(jìn)制,符號(hào)會(huì)改變,會(huì)變?yōu)樨?fù)數(shù)
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
// MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
二、LinkedList
// LinkedList: 使用雙向鏈表結(jié)構(gòu),增刪快,查找慢
// (這種結(jié)構(gòu)和ArrayList的數(shù)組結(jié)構(gòu)正好是互補(bǔ)狀態(tài))
LinkedList<Integer> ll = new LinkedList<>();
// 模擬棧結(jié)構(gòu)
// 壓棧
ll.push(100);
ll.push(200);
// 彈棧
Integer i = ll.pop();
// 200
System.out.println(i);
// 1
System.out.println(ll.size());
// 下面注釋參考 不建議使用
// 添加集合中第一個(gè)元素
// ll.addFirst(100);
// ll.addFirst(200);
// 移除集合中第一個(gè)元素
// Integer removeData = ll.removeFirst();
// 200
// System.out.println(removeData);
// 1
// System.out.println(ll.size());
三、Vector
用法和ArrayList基本一致,是線程安全的。
// 10 初始化長(zhǎng)度 20 擴(kuò)容增量 此處是相較于ArrayList不同之處
List<Integer> v = new Vector<>(10, 20);
v.add(100);
v.add(200);
四、Iterator和ListIterator
// Iterator 迭代器 作用遍歷集合
// Iterator迭代Collection下List和Set ListIterator迭代List下面的集合
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Iterator<Integer> iterator = list.iterator();
iterator.next();
// 必須要有值才能移除即前面調(diào)用next()方法,當(dāng)然沒(méi)值也會(huì)報(bào)錯(cuò)
iterator.remove();;
// 4
System.out.println(list.size());
// 判斷迭代器下個(gè)是否有值
while(iterator.hasNext()) {
// 迭代器往下走,并取值
Integer i = iterator.next();
// 輸出 2 3 4 5
System.out.println(i);
}
// 用法和iterator差不多
ListIterator<Integer> listIterator = list.listIterator();
// 獲取向上走的值
listIterator.hasPrevious();
// 添加
listIterator.add(10);
// 設(shè)置
listIterator.next();
listIterator.set(200);
listIterator.previous();
// 5
System.out.println(list.size());
while(listIterator.hasNext()) {
// 輸出 200 3 4 5
System.out.println(listIterator.next());
}
五、Set
Set集合是沒(méi)有重復(fù)的元素,包括null只會(huì)存在一個(gè)
5.1 HashSet
// HashSet是散列存放的數(shù)據(jù)結(jié)構(gòu)(哈希表)
// 本質(zhì)是 map = new HashMap<>()
// 由于已經(jīng)存在雙值存儲(chǔ)的哈希表 所以這邊重復(fù)利用了形成現(xiàn)在的單值存儲(chǔ)的哈希表
Set<String> set = new HashSet<>();
// map.put(e, PRESENT)
set.add("人有悲歡離合");
set.add("月有陰晴圓缺");
set.add("但愿人長(zhǎng)久");
set.add("但愿人長(zhǎng)久");
set.add("千里共嬋娟");
set.add("千里共嬋娟");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
5.2 TreeSet
public static void main(String[] args) {
// TreeSet 使用二叉樹(shù)進(jìn)行存儲(chǔ)的 有序(自然順序)
Set<Person> set = new TreeSet<>();
Person p1 = new Person("張三", 13);
Person p2 = new Person("李四", 14);
Person p3 = new Person("麻五", 14);
set.add(p1);
set.add(p2);
set.add(p3);
// 遍歷前需制定自己的排序規(guī)則, 否則可能報(bào)錯(cuò)
// Person{name='張三', age=13}
// Person{name='李四', age=14}
// 比較規(guī)則相同的值,不被儲(chǔ)存
for (Person p : set) {
System.out.println(p);
}
// set.add("C");
// set.add("B");
// set.add("A");
// set.add("D");
// A B C D
// Iterator<String> iterator = set.iterator();
// while(iterator.hasNext()) {
// System.out.println(iterator.next());
// }
}
static class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public int compareTo(Person o) {
// this與0比較
// 返回this小/0/大
if (this.age > o.age) {
return 1;
} else if (this.age == o.age) {
return 0;
}
return -1;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
六、Map
Map(Mapping 映射)集合存儲(chǔ)的是 鍵值對(duì) 數(shù)據(jù),Map的鍵不可重復(fù)。
影響HashMap的實(shí)例化性能的是初始容量和負(fù)載因子。
HashMap/Hashtable/ConcurrentHashMap TreeMap/LinkedHashMap使用方法基本一致。
HashMap是線程不安全,效率高。HashTable線程安全, 效率低。
ConcurrentHashMap采用分段鎖機(jī)制,保證線程安全,效率較高。
TreeMap是有序的排。
LinkedHashMap存儲(chǔ)有序。
6.1 HashMap
Map<String, String> map = new HashMap<>();
// 存值
map.put("k1", "v1");
// 取值 v1
System.out.println(map.get("k1"));
map.put("k2", "v2");
// 遍歷
Set<String> set = map.keySet();
for (String key : set) {
// k1->v1
// k2->v2
System.out.println(key + "->" + map.get(key));
}
// 轉(zhuǎn)為Collection集合
Collection<String> c = map.values();
for (String s : c) {
System.out.println(s);
}
HashMap源碼粗解析
// 構(gòu)造方法
public HashMap() {
// 默認(rèn)加載因子0.75f
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public V put(K key, V value) {
// 先計(jì)算鍵的hash值,然后調(diào)用putVal
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// n是桶(數(shù)組)的長(zhǎng)度
Node<K,V>[] tab; Node<K,V> p; int n, i;
// table是默認(rèn)的16個(gè)長(zhǎng)度的數(shù)組賦值給tab
if ((tab = table) == null || (n = tab.length) == 0)
// resize擴(kuò)容算法 n擴(kuò)容之后的長(zhǎng)度
n = (tab = resize()).length;
// (n - 1) & hash 是取余后的長(zhǎng)度 數(shù)組下標(biāo)沒(méi)有值直接賦值
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
// key存在新值覆蓋老值
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 判斷是樹(shù)節(jié)點(diǎn) 按紅黑樹(shù)套路進(jìn)行存儲(chǔ)
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// 鏈表套路進(jìn)行賦值
else {
for (int binCount = 0; ; ++binCount) {
// 非重復(fù)值操作
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// 這邊是二叉樹(shù)操作
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// 重復(fù)值操作
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 前面e被賦值,進(jìn)入此方法
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
// 增加修改次數(shù)
++modCount;
// 判斷是否到了臨界值
if (++size > threshold)
// 擴(kuò)容
resize();
afterNodeInsertion(evict);
return null;
}
總結(jié)
在文章的最后作者為大家整理了很多資料!包括java核心知識(shí)點(diǎn)+全套架構(gòu)師學(xué)習(xí)資料和視頻+一線大廠面試寶典+面試簡(jiǎn)歷模板+阿里美團(tuán)網(wǎng)易騰訊小米愛(ài)奇藝快手嗶哩嗶哩面試題+Spring源碼合集+Java架構(gòu)實(shí)戰(zhàn)電子書(shū)等等!
歡迎關(guān)注公眾號(hào):前程有光,領(lǐng)?。?/p>