一、ArrayList
数组汇合利用
// ArraysList 增删慢 查问快
// 依据源码 无参构造方法创立进去的是长度为 0 的数组 {}
List<Integer> list = new ArrayList<>();
// 此时 add 办法进行源码扩容
list.add(100);
System.out.println(list.get(0));
add() 办法扩容源码
public boolean add(E e) {
// 不须要关注
modCount++;
// e 对象 elementData 汇合数组元素 size 以后数组长度
add(e, elementData, size);
// 不论成功失败 均返回 true
return true;
}
private void add(E e, Object[] elementData, int s) {
// 满足条件 进入扩容算法 不然就进行失常赋值操作
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
// 至多须要加一个长度
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;
// 新长度加上旧长度的 0.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// DEFAULT_CAPACITY 默认长度 10
return Math.max(DEFAULT_CAPACITY, minCapacity);
// 超出最大二进制,符号会扭转,会变为正数
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: 应用双向链表构造,增删快,查找慢
//(这种构造和 ArrayList 的数组构造正好是互补状态)LinkedList<Integer> ll = new LinkedList<>();
// 模仿栈构造
// 压栈
ll.push(100);
ll.push(200);
// 弹栈
Integer i = ll.pop();
// 200
System.out.println(i);
// 1
System.out.println(ll.size());
// 上面正文参考 不倡议应用
// 增加汇合中第一个元素
// ll.addFirst(100);
// ll.addFirst(200);
// 移除汇合中第一个元素
// Integer removeData = ll.removeFirst();
// 200
// System.out.println(removeData);
// 1
// System.out.println(ll.size());
三、Vector
用法和 ArrayList 基本一致,是线程平安的。
// 10 初始化长度 20 扩容增量 此处是相较于 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();
// 必须要有值能力移除即后面调用 next() 办法,当然没值也会报错
iterator.remove();;
// 4
System.out.println(list.size());
// 判断迭代器下个是否有值
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);
// 设置
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 汇合是没有反复的元素,包含 null 只会存在一个
5.1 HashSet
// HashSet 是散列寄存的数据结构(哈希表)// 实质是 map = new HashMap<>()
// 因为曾经存在双值存储的哈希表 所以这边反复利用了造成当初的单值存储的哈希表
Set<String> set = new HashSet<>();
// map.put(e, PRESENT)
set.add("人有酸甜苦辣");
set.add("月有阴晴圆缺");
set.add("但愿人长久");
set.add("但愿人长久");
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 应用二叉树进行存储的 有序(天然程序)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);
// 遍历前需制订本人的排序规定, 否则可能报错
// Person{name='张三', age=13}
// Person{name='李四', age=14}
// 比拟规定雷同的值,不被贮存
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 映射)汇合存储的是 键值对 数据,Map 的键不可反复。
影响 HashMap 的实例化性能的是初始容量和负载因子。
HashMap/Hashtable/ConcurrentHashMap TreeMap/LinkedHashMap 应用办法基本一致。
HashMap 是线程不平安,效率高。HashTable 线程平安,效率低。
ConcurrentHashMap 采纳分段锁机制,保障线程平安,效率较高。
TreeMap 是有序的排。
LinkedHashMap 存储有序。
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));
}
// 转为 Collection 汇合
Collection<String> c = map.values();
for (String s : c) {System.out.println(s);
}
HashMap 源码粗解析
// 构造方法
public HashMap() {
// 默认加载因子 0.75f
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public V put(K key, V value) {
// 先计算键的 hash 值,而后调用 putVal
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// n 是桶(数组)的长度
Node<K,V>[] tab; Node<K,V> p; int n, i;
// table 是默认的 16 个长度的数组赋值给 tab
if ((tab = table) == null || (n = tab.length) == 0)
// resize 扩容算法 n 扩容之后的长度
n = (tab = resize()).length;
// (n - 1) & hash 是取余后的长度 数组下标没有值间接赋值
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;
// 判断是树节点 按红黑树套路进行存储
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// 链表套路进行赋值
else {for (int binCount = 0; ; ++binCount) {
// 非反复值操作
if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);
// 这边是二叉树操作
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// 反复值操作
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 后面 e 被赋值,进入此办法
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
// 减少批改次数
++modCount;
// 判断是否到了临界值
if (++size > threshold)
// 扩容
resize();
afterNodeInsertion(evict);
return null;
}
总结
在文章的最初作者为大家整顿了很多材料!包含 java 外围知识点 + 全套架构师学习材料和视频 + 一线大厂面试宝典 + 面试简历模板 + 阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题 +Spring 源码合集 +Java 架构实战电子书等等!
欢送关注公众号:前程有光,支付!