Java笔记-集合

Java笔记-集合专题

集合体系图

集合主要分为两种:

​ Collection: List、Set;属于单列集合

​ Map:双列集合,存放Key-Value

image-20210506192747886

image-20210506192801220

Collection

这些是List和Set都继承了的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
ArrayList arrayList = new ArrayList();
arrayList.add("阿武");
arrayList.add(18);
arrayList.add(0.8f);
arrayList.add(true);
arrayList.add(true);
System.out.println(arrayList);
arrayList.remove(2);
System.out.println(arrayList);
arrayList.remove(true);
System.out.println(arrayList);
System.out.println(arrayList.size());
// contains();addAll();clearAll();

image-20210506203531547

遍历Collection

1
2
3
4
5
6
7
8
9
10
11
12
13
Iterator iterator = arrayList.iterator();
// 快捷键itit
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("obj: " + next);
}

// 使用增强for替换迭代器,其底层仍是迭代器
// 快捷键arrayList.for
System.out.println("增强for迭代===========");
for (Object o : arrayList) {
System.out.println("obj:" + o);
}

ArrayList底层

image-20210506212823395

上面的transient表示:被修饰的属性是瞬间的,短暂的,不会被序列化。

使用无参构造器创建ArrayList:

1
2
3
4
5
6
7
8
public class ArrayListSource {
public static void main(String[] args) {
ArrayList list = new ArrayList();
for (int i = 0; i < 12; i++) {
list.add(i);
}
}
}

使用无参构造器,首先创建了一个空的elementData数组;从这里可见:ArrayList的底层是通过数组实现的,而这个elementData就是存放数据的数组。

image-20210506213448685

image-20210506213539990

然后我们看添加元素的方法:

e:代表要添加的元素;

modCount:记录集合被修改的次数

在这个add中其实调用了另一个add方法,而这第二个是真正实现添加操作的。

image-20210506213916692

s:指示在ArrayList中添加的元素个数;

elementData.length:表示当前的容量;

当两者相等,表示当前容量不够,需要自动增加容量了。–>grow()

确保有剩余的空间来添加元素后,才进行真正的添加元素:

elementData[s]=e; //添加到尾部

size = s+1; //更新元素个数

image-20210506214028824

s==elementData.length:需要扩容时

扩容的方法:

minCapacity:指示当前ArrayList所需要的最小容量,添加当前这个元素所需要的容量。

newCapacity():计算自动扩容后的容量

扩容:将原数组复制到一个更大的数组–》Array.copyOf(),这样可以保留原先的数据

image-20210506214058167

image-20210506214115602

最后看下扩容的容量是怎么算的–》newCapacity()

第一次扩容情况特殊,通过方法中第二条语句计算得到的newCapacity仍然是0,所以要通过下面的判断来进行特殊处理。

后面的就是按照:newCapacity = oldCapacity + (oldCapacity>>1); // 等价于扩容到原来容量的1.5倍

image-20210506214231510

1
2
DEFAULT_CAPACITY = 10;					//默认容量是10
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 // MAX_VALUE = 0x7fffffff=2147483647

image-20210506214409897

使用带参构造器

使用带参数的构造器时,elementData的默认容量就是所传的参数,后面容量的自动增长也是增加到原来的1.5倍。

image-20210507091027392

image-20210507091322938

image-20210507091549618

Vector底层

image-20210507173525791

无参构造器

image-20210507173912482

从源码中,我们可以看到,不管我们使用的是有参还是无参的构造器,它最终都是通过Vector(int initialCapacity, int capacityIncrement)实现的;而且使用无参构造器,实际是创建了一个默认容量为10的Vector。

image-20210509100555854

image-20210509100609556

image-20210509100622650

我们再来看下add()方法,感觉和ArrayList的add()很类似,不同的是,Vector扩容时,时扩容到原来的2倍。

image-20210507175430706

image-20210507175448610

image-20210507175504372

image-20210507175516183

image-20210507175535486

image-20210507175656167

LinkedList底层

底层实现了双向链表和双端队列的特点。

线程不安全,没有实现同步。

image-20210507181602078

image-20210507181850120

image-20210507181906299

image-20210507232843541

1
2
3
4
5
6
7
8
9
10
public class LinkedListSource {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
for (int i = 0; i < 5; i++) {
linkedList.add(i);
}
linkedList.remove(3);
}
}

构造器

首先看下LinkedList的构造器,就是一个空的方法。执行后给属性进行初始化工作。

image-20210509101851357

image-20210509102134987

add()

image-20210509102236045

image-20210509102516662

添加第一个元素时,链表的头尾指针都是指向这个元素。

image-20210509102619712

试着再添加一个元素,可以看到他们确实形成了双向链表的结构。

image-20210509102923166

image-20210509103039749

remove()

image-20210509103340598

image-20210509103540914

image-20210509103527755

checkElementIndex()是检查所要删除的元素下标是否是有效的。

unlink(Node x)来删除链表中的元素,让其前面的元素,指向x.next,让后面的元素指向x.pre,让x.item=null。

image-20210509104940970

Set

Set和List一样,都继承自Collection,所以常用方法和Collection一样。

遍历方式也一样,但是不能使用【索引】的方式来遍历,因为Set中元素是无序的。底层的实现不再是数组,而是数组+链表。

不能存放重复的元素;

是无序的:添加的顺序与取出的顺序不同,但是每次取出的顺序是固定的;

HashSet

HashSet底层是HashMap,-》

(数组+链表+红黑树)jdk8.0

(数组+链表)jdk7.0

image-20210509110025408

LinkedHashSet

其底层是LinkedHashMap;(和HashSet维护的是HashMap结构)

底层维护一个数组+双向链表;

由于有了双向链表,这样就可以让插入顺序与取出的顺寻一致;(和HashSet不同)

Map

image-20210510101714810

image-20210506192801220

HashMap

初始大小16,

加载应子:0.75

Hashtable

key、value均不允许为空,NullPointerException;

是线程安全的;

image-20210510112226641

底层:Hashtable$Entry[],初始大小:11;

当count>=threshold时,

扩容算法:new = (old<<2)+1;新容量 = 原来的*2+1;

image-20210510151249644

Properties

image-20210510151626481

总结

image-20210510152742275


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!