6
6
7
7
#### List
8
8
9
-
9
+ > 代表 ** 有序、可重复 ** 的集合
10
10
11
11
##### ArrayList
12
12
13
-
13
+ 底层结构是 ** 数组 ** ,可用索引实现快速查找;是动态数组,相比于数组容量可实现动态增长
14
14
15
15
##### LinkedList
16
16
17
-
17
+ 底层结构是 ** 链表 ** ,增删速度快;是一个 ** 双向循环 ** 链表,也可以被当作堆栈、队列或双端队列
18
18
19
19
#### Set
20
20
21
-
21
+ > 代表 ** 无序、不可重复 ** 的集合
22
22
23
23
##### HashSet
24
24
25
-
25
+ 不能保证元素的排列顺序;使用 ** Hash算法 ** 来存储集合中的元素,有良好的存取和查找性能;通过 ` equal() ` 判断两个元素是否相等,并两个元素的 ` hashCode() ` 返回值也相等
26
26
27
27
##### TreeSet
28
28
29
-
29
+ 是SortedSet接口的实现类,根据元素 ** 实际值的大小 ** 进行排序;采用 ** 红黑树 ** 的数据结构来存储集合元素;支持两种排序方法: ** 自然排序 ** (默认情况)和 ** 定制排序 ** 。前者通过实现 ** Comparable接口 ** 中的 ` compareTo() ` 比较两个元素之间大小关系,然后按升序排列;后者通过实现 ** Comparator接口 ** 中的 ` compare() ` 比较两个元素之间大小关系,实现定制排列
30
30
31
31
### Map
32
32
33
-
33
+ > 代表具有 ** 映射关系 ** 的集合
34
34
35
35
##### HashMap
36
36
37
+ 实现了Map、** Cloneable** (能被克隆)、** Serializable** (支持序列化)接口; ** 非线程安全** ;允许存在一个为null的key和任意个为null的value;采用** 链表散列** 的数据结构,即数组和链表的结合;初始容量为16,填充因子默认为0.75,扩容时是当前容量翻倍,即2 capacity
38
+
39
+ ###### put
37
40
41
+ 首先判断key是否为空,为空则直接调用putForNullKey(),不为空则计算key的hash值得到该元素在数组中的下标值;如果数组在该位置处没有元素,就直接保存;如果有,还要比较是否存在相同的key,存在的话就覆盖原来key的value,否则将该元素保存在链头,先保存的在链尾
42
+
43
+ ###### get
44
+
45
+ 计算key的hash值找到在数组中的对应的下标值,返回该key对应的value即可,如果有冲突就遍历该位置链表寻找key相同的元素并返回对应的value
46
+
47
+ ###### other
48
+
49
+ - 采用** 链表散列(拉链表)** 的数据结构,即数组和链表的结合,在Java8后又结合了红黑树,当链表元素超过8个将链表转换为红黑树
50
+ - 每次扩容需要重新计算元素Hash值,损耗性能,所以建议在使用HashMap时,最好先估算Map的大小,设置初始值,避免频繁扩容
38
51
39
52
##### LinkedMap
40
53
54
+ 是有序的HashMap,默认为插入顺序,还可以是访问顺序,基本原理是其内部通过Entry维护了一个双向链表,负责维护Map的迭代顺序
55
+
56
+
57
+
58
+ ##### ConcurrentHashMap
59
+
60
+ 线程安全的HashMap,它采取锁分段技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
61
+
62
+ ### 抽象类和接口
63
+
64
+ #### 相同点
65
+
66
+ - 不能实例化
67
+ - 抽象的方法如果
68
+
69
+ #### 不同点
70
+
71
+ - 抽象类用于** 继承** (单继承),接口用于** 实现** (多实现)
72
+ - 抽象类是对** 类** 的抽象,接口是对于** 行为** 的抽象
73
+ - 抽象类可以有** 成员变量,非抽象方法** ,而接口不允许有
74
+ - 抽象类可以有构造方法,而接口不允许有
75
+
41
76
42
77
43
78
### 四大组件+
132
167
133
168
### 多线程
134
169
170
+ #### 线程的几个状态
171
+
172
+ ##### 新建:NEW
173
+
174
+ 线程刚被创建出来,尚未启动
175
+
176
+ ##### 运行:RUNNABLE
177
+
178
+ 包括正在执行(Running)和等待着CPU为它分配执行时间(Ready)两种
179
+
180
+ ##### 无限期等待:WAITING
181
+
182
+ 该线程不会被分配CPU执行时间,要等待被其他线程显式地唤醒,通过未设置timout的` Object.wait ` or ` Thread.join ` 进入该状态
183
+
184
+ ##### 限期等待:TIMED_WAITING
185
+
186
+ 该线程不会被分配CPU执行时间,但在一定时间后会被系统自动唤醒,通过设置timout的` Object.wait ` or ` Thread.join ` ,` Thread.sleep ` 进入该状态
187
+
188
+ ##### 阻塞:BLOCKED
189
+
190
+ 线程被阻塞。和等待状态不同的是,阻塞状态表示在等待获取到一个** 排他锁** ,在另外一个线程放弃这个锁的时候发生;而等待状态表示在等待一段** 时间** 或者** 唤醒动作** 的发生,在程序等待进入同步区域的时候发生
191
+
192
+ ##### 结束:TERMINATED
193
+
194
+ 线程已经结束执行
195
+
196
+ <img src =" F:\Note\Android\线程状态.jpg " style =" zoom :50 ;" />
197
+
135
198
#### synchornized
136
199
200
+ ** 悲观锁** 策略,对线程加独占锁,被它修饰的类/方法/变量只允许一个线程访问,在释放锁之前会将工作内存新值更新到主存中,虽然无法禁止指令重排和处理器优化,但由于是只允许一个线程访问,可以保证** 原子性,可见性,有序性**
201
+
202
+ #### volatile
203
+
204
+ 保证新值能** 立即** 同步到主内存,且每次使用前立即从主内存刷新,可以保证** 可见性,有序性**
205
+
206
+ #### atomic
207
+
208
+ #### 锁
209
+
210
+ ##### 悲观锁
211
+
212
+ 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。** synchronized** 的实现就是悲观锁
213
+
214
+ 存在一些问题:
215
+
216
+ - 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题
217
+ - 一个线程持有锁会导致其它所有需要此锁的线程挂起,有潜在的** 死锁** 风险
218
+ - 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险
219
+
220
+ ##### 乐观锁
221
+
222
+ 假设认为数据一般情况下不会产生并发冲突,所以在数据进行提交更新的时候,才会正式对数据是否产生并发冲突进行检测,如果发现并发冲突了,则让返回用户错误的信息,让用户决定如何去做,** CAS** 是这种思想的一种实现方式
223
+
137
224
#### 生产者消费者
138
225
139
- Handler
226
+ #### Handler
140
227
141
- AsyncTask
228
+ #### AsyncTask
142
229
143
230
#### Thread.join
144
231
@@ -195,8 +282,16 @@ public static void main(String[] args) {
195
282
196
283
#### 内存泄漏
197
284
285
+ 指程序在申请内存后,** 无法释放** 已申请的内存空间。简单地说,发生内存泄漏是由于长周期对象持有对短周期对象的引用,使得短周期对象不能被及时回收
286
+
287
+ - 单例模式下持有来自` Activity ` 的` Content ` ,导致无法回收资源,改用` context.getApplicationContext() `
288
+ - 内部类(` Thread ` or ` Handler ` )持有` Activity ` 的引用,导致无法回收资源,改用静态内部类 or 弱引用
289
+ - ` Cursor ` ,` File ` 等资源未关闭的原因导致
290
+
198
291
#### 内存溢出
199
292
293
+ 指程序在申请内存时,没有足够的内存空间供其使用,** 内存泄漏** 是导致其出现的主要原因
294
+
200
295
#### 布局优化
201
296
202
297
##### include
@@ -207,6 +302,25 @@ public static void main(String[] args) {
207
302
208
303
#### 数据结构优化
209
304
305
+ ##### ArrayMap
306
+
307
+ 相对于HashMap的实现,更加节省内存,内部通过2个数组来实现,** int[ ] ** 存放KEY的hashcode,** Object[ ] ** 长度是上个数组的** 2** 倍,存放KEY和VALUE,适合** 数据量不大的场景**
308
+
309
+ - put:通过对KEY的hashcode进行二分查找,` indexOf ` 方法,如果出现了hash冲突,则从目标点向两头遍历,找到正确的index
310
+
311
+ - ** Object[ ] ** 存放数据的位置是KEY=Object[ ** index\* 2** ]
312
+ ,VALUE=KEY=Object[ ** index\* 2+1** ]
313
+
314
+ - 收缩操作:当hash长度大于8,并且存放的数据长度小于** 1/3** 时,触发数组拷贝收缩操作
315
+
316
+ ##### SparseArray
317
+
318
+ 又称稀疏数组,内部通过2个数组来存储key和value,可替代key为int、value为Object的HashMap
319
+
320
+ - 更加节省内存
321
+ - 由于key指定为int,能节省int和Integer的装箱拆箱操作带来的性能消耗
322
+ - 扩容时只需要数组拷贝工作,而不需重建哈希表
323
+
210
324
#### 代码优化
211
325
212
326
### 屏幕适配
0 commit comments