-
Notifications
You must be signed in to change notification settings - Fork 0
/
30 面试
365 lines (299 loc) · 24.9 KB
/
30 面试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
30.面试
一、JAVA 部分
A类 学前基础
https://blog.csdn.net/m0_37194191/article/details/87785045
https://zhuanlan.zhihu.com/p/64147696
1.类的三大特性:继承、封装、多态。
继承 : 子类继承父类的属性和行为,并能根据自己的需求扩展出新的属性和行为,提高了代码的可复用性。
封装 : 隐藏了类的内部实现机制,只提供外部需要的方法和成员。
多态 : 指同一个消息被不同的对象接收时,可解释为不同的含义。继承是多态的前提,多态是指父类或者接口的引用指向了子类对象。
继承前提,方法重写,父类或接口引用指向子类对象。
2.接口(Interface)和抽象类(Abstract Class)的区别
接口:是一个方法的集合,所有方法都公开。
抽象类:是类,可以有成员变量、正常方法,而有任一抽象方法的都是抽象类。
共同点:1.不能被序列化。 2.实例化之前都需要先实现接口方法或抽象方法。
不同点:
1)接口只有定义不能有方法的实现,而抽象类可以有定义和实现。
2)一个类可以实现多个接口但是可以继承多个实现类。
3)接口强调特定功能的实现,抽象类强调所属关系。
4)接口被运用于实现比较常用的功能便于日后维护或者添加删除方法,抽象类充当于公共类角色。
3.重写(Override)和重载(Overload)的区别
重写:对继承的父类方法内部进行重新实现
重载:重新定义方法名相同,但参数不一样的方法。
4.Serializable和Parcelable的区别
Serializable:Java序列化接口,在硬盘上读写,读写过程中有大量的临时变量生成,内部执行大量的I/O操作,效率低。
Parcelable:Android序列化接口,效率高,使用麻烦,在内存中读写,对象不能保存在磁盘中。
5.HashMap与HashTable的区别
a.HashMap不是线程安全的,效率高一些;HashTable是线程安全的
b.HashMap的key和value都可以是null值,HashTable不允许有null的键和值。
c.HashTable是继承自Dictionary类,而HashMap是继承自AbstractMap类,都实现了Map接口。
d.是否提供contains方法
e.两个遍历方式的内部实现不同
f.Hash值不同
g.内部实现使用的数组初始化和扩容方式不同
6.Java集合框架中有哪些类?都有什么特点?
可将Java集合框架大致分为Set、List、Queue和Map四种体系。
Set:代表无序、不可重复的集合,常见的如HashSet、TreeSet。
List:代表有序、可重复的集合,常见的如ArrayList、双向链表LinkedList、可变数组Vector
Map:代表具有映射关系的集合,常见的如HashMap、HashTable、LinkedHashMap、TreeMap
Queue:代表一种队列集合。
7.ArrayList和LinkedList的区别
ArrayList的底层结构是数组,可用索引实现快速查找;是动态数组,相比于数组,容量可以实现动态增长。
LinkedList底层结构是链表,增删速度快;是一个双向循环链表,也可以被当做堆栈、队列或双端队列。
8. HashMap 中的 key若 Object类型, 则需实现哪些方法
hashCode和equals
9. HashMap线程安全的解决方案
使用Collections.synchronizedMap()方法,该方法的实现方式是使用synchronized关键字
使用ConcurrentHashMap,性能比Collections.synchronizedMap()更好
10.List和数组的互相转换/String转换成数组
String[] a = list.toArray(new String[size]));
List list = Arrays.asList(array);
char[] char = string.toCharArray();
11.run和start的区别
run没有开辟新的栈空间,没有新线程,都是主线程在执行
start开辟了新的栈空间,在新的栈空间启动run()方法
12. finally 语句一定会执行吗
在极特殊的情况下可能不执行
a.调用了System.exit()方法
b.JVM崩溃了
13. 抽象类和接口的区别
一个类只能继承单个类,但是可以实现多个接口
接口强调特定功能的实现,而抽象类强调所属关系
抽象类中的所有方法并不一定要是抽象的,你可以选择在抽象类中实现一些基本的方法。而接口要求所有的方法都必须是抽象的
14.内存溢出和内存泄漏
内存溢出:指程序在申请内存时,没有足够的空间供其使用
内存泄漏:指程序分配出去的内存不再使用,无法进行回收
15.sleep() 和 wait() 有什么区别?
1.这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类。
2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
3.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
4. Sleep需要捕获异常,而wait不需要
16.线程中wait,join,sleep,yield, notify,notifyall,synchronized,区别及联系
1).sleep()方法
在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。sleep()使当前线程进入阻塞状态,在指定时间内不会执行。
2).wait()方法
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。
唤醒当前对象锁的等待线程使用notify或notifyAll方法,waite() 和notify()必须在synchronized函数或synchronized block中进行调用。
yield方法暂停当前正在执行的线程对象。yield()只是使当前线程重新回到可执行状态,所以执行
3)yield()的线程有可能在进入到可执行状态后马上又被执行。yield()只能使同优先级或更高优先级的线程有执行的机会。
4).join方法
等待该线程终止。等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测
17.Synchronized如何使用
Synchronized是Java的关键字,是一种同步锁,它可以修饰的对象有以下几种
修饰代码块:该代码块被称为同步代码块,作用的主要对象是调用这个代码块的对象
修饰方法:该方法称为同步方法,作用的主要对象是调用这个方法的对象
修饰静态方法:作用范围为整个静态方法,作用的主要对象为这个类的所有对象
修饰类:作用范围为Synchronized后面括号括起来的部分,作用的主要对象为这个类的所有对象
18.Synchronized和Lock的区别
相同点:Lock能完成Synchronized所实现的所有功能
不同点:
Synchronized是基于JVM的同步锁,JVM会帮我们自动释放锁。Lock是通过代码实现的,Lock要求我们手工释放,必须在finally语句中释放。
Lock锁的范围有局限性、块范围。Synchronized可以锁块、对象、类
Lock功能比Synchronized强大,可以通过tryLock方法在非阻塞线程的情况下拿到锁
19.多线程的等待唤醒主要方法
void notify():唤醒在此对象监视器上等待的单个线程
void notifyAll():唤醒在此对象监视器上等待的所有线程
void wait():导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法
void wait(long timeout):导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量
void wait(long timeout, int nanos):导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量
20.什么是类加载器
ClassLoader是用来动态加载class文件到内存中
21.双亲委托模型(父委托加载机制)
当加载一个类时,首先会判断当前类是否已经被加载,如果被加载直接返回当前类加载器,如果没有被加载,则把机会让给父类,先让父类加载,
若是父类中不能加载,则会去找到Bootstrap加载器,
如果Bootstrap加载器加载失败,则会退回上层,自己通过findClass自己去加载对应的路径(这是孝顺型的,先想到父类,但是他们不是通过继承来实现的)
22.类加载过程
加载:将类的信息从文件中获取并且载入到JVM内存中
验证:检查读入的结构是否符合JVM规范的描述
准备:分配一个结构用来存储类信息
解析:把这个类的常量池的所有符号引用改变成直接引用
初始化:执行静态初始化程序、类构造器方法的过程
23.类加载主要方法的区别
findClass():查找指定路径下的class文件
loadClass():加载class字节码文件
defineClass():将字节数组流转换成字节码
24.http与https的区别
HTTP协议以明文方式发送内容,不提供任何方式的数据加密
HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)
HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
25.WebSocket和Socket的区别
a.socket 其实并不是一个协议,而是为方便使用TCP、UDP而抽象出来的一层,是位于应用层和传输层之间的一组接口。
b.WebSocket则是一个典型的应用层协议。是TCP/ip协议的再封装。
c.websocket 是一个完整的应用层协议,有一套标准的api,相对sockect更灵活。
d.websocket是为了解决http单向传输。
e.WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。
26.Error和Exception有什么区别?
答:Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;
比如内存溢出,不可能指望程序能处理这样的情况;
Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;
也就是说,它表示如果程序运行正常,从不会发生的情况。
27.创建线程池有哪几种方式?
①. newFixedThreadPool(int nThreads)
创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。
②. newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。
③. newSingleThreadExecutor()
这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。
④. newScheduledThreadPool(int corePoolSize)
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
28.线程池都有哪些状态?
线程池有5种状态:Running、ShutDown、Stop、Tidying、Terminated。
29.创建线程有哪几种方式?
创建线程有三种方式:
继承 Thread 重写 run 方法;
实现 Runnable 接口;
实现 Callable 接口
30.线程有几种状态
NEW 尚未启动
RUNNABLE 正在执行中
BLOCKED 阻塞的(被同步锁或者IO锁阻塞)
WAITING 永久等待状态
TIMED_WAITING 等待指定的时间重新被唤醒的状态
TERMINATED 执行完成
31.synchronized 和 volatile 的区别是什么?
volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。
volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。
volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
32.synchronized 和 ReentrantLock 区别是什么?
主要区别如下:
ReentrantLock 使用起来比较灵活,但是必须有释放锁的配合动作;
ReentrantLock 必须手动获取与释放锁,而 synchronized 不需要手动释放和开启锁;
ReentrantLock 只适用于代码块锁,而 synchronized 可用于修饰方法、代码块等。
33.简述 tcp 和 udp的区别?
tcp 和 udp 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。
两者的区别大致如下:
tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接;
tcp 提供可靠的服务(数据传输),udp 无法保证;
tcp 面向字节流,udp 面向报文;
tcp 数据传输慢,udp 数据传输快;
34.Vector 与 Array 的区别
1)ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。
2)Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。
35.JVM如何加载一个类的过程,双亲委派模型中有哪些方法
类加载过程:加载、验证(验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害)、
准备(准备阶段为变量分配内存并设置类变量的初始化)、
解析(解析过程是将常量池内的符号引用替换成直接引用)、
初始化。
双亲委派模型中方法:双亲委派是指如果一个类收到了类加载的请求,不会自己先尝试加载,先找父类加载器去完成。
当顶层启动类加载器表示无法加载这个类的时候,子类才会尝试自己去加载。
当回到最开的发起者加载器还无法加载时,并不会向下找,而是抛出ClassNotFound异常。
36.普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化
37.Iterator 怎么使用?有什么特点?
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
38.Iterator 和 ListIterator 有什么区别?
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
39.线程安全在三个方面体现:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
40.什么是类反射
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,
从而获取t对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。
通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
41.并发和并行的区别
并发:(在一个时间段内同时执行多件事)如单核cpu以时间片的方式让多个线程轮循执行,在外界看来他们是同时执行的
并行:(在一个时刻同时执行多件事)多核cpu每个核运行一个App,他们是真正的同时执行
51.Java中的volatile 变量是什么
volatile是一个修饰符,只能修饰成员变量
volatile保证了变量的可见性(A线程的改变,B线程马上可以获取到)
volatile禁止进行指令重排序
52.sleep和wait方法的对比
两个方法都是暂停线程,释放cpu资源给其他线程
sleep是Thread的静态方法,wait是Object的方法。
sleep使线程进入阻塞状态;wait使线程进入等待状态,靠其他线程notify或者notifyAll来改变状态
sleep可以在任何地方使用,必须捕获异常;而wait必须在同步方法或者同步块中使用,否则会抛出运行时异常
最重要的:sleep继续持用锁,wait释放锁
扩展:yield停止当前线程,让同优先级或者优先级高的线程先执行(但不会释放锁);
join方法在某一个线程的执行过程中调用另一个线程执行,等到被调用的线程执行结束后,再继续执行当前线程
53.为什么wait和notify方法要在同步块中调用
java规定必须在同步块中,不在同步块中会抛出异常
如果不在同步块中,有可能notify在执行的时候,wait没有收到陷入死锁
54.synchronized关键字的用法
synchronized 用于线程同步
可以修饰方法
可以修饰代码块
当持有的锁是类时,那么所有实例对象调用该方法或者代码块都会被锁
55.synchronized 在静态方法和普通方法的区别
synchronized修饰静态方法时,锁是类,所有的对象实例用同一把锁修饰普通方法时,锁是类的实例
56. 当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
不能。其它线程只能访问该对象的非同步方法。第一个线程持有了对象锁,第二个线程的同步方法也需要该对象的锁才能运行,只能在锁池中等待了。
二、Android部分
A类 学前基础
略.
B类 基础知识
1.跨进程通信的几种方式
(1.Intent 最后也是基于Binder机制 还有intent+Bundle
(2.广播 Brocadcast/BroadcastReceiver 最后也是基于Binder机制
(3.IBinder 更是基于Binder机制(3种方式)
继承Binder类、
使用Messenger类、
使用AIDL。
(4.使用数据存储技术
file,contentProvider,数据库存储数据
(5. 网络socket.
各自特点:
1.intent,常用于组件间启动调用,传递附加数据。eg:调用启动同个应用或不同应用的Activity。
2.广播, 不在一个应用,常用于系统或不同应用间的信息传递。
3.Ibinder 常用于IPC,是基于ServiceManager对象。
4.使用数据存储技术。常用于数据量大,数据公开,速度要求不高。
2.Binder机制
组成:Client\Server\ServerManager\BinderDriver
android 大部分的IPC是基于Binder实现的。Binder为同步通信、高效,为系统IPC.
Binder的用户空间为每个进程维护着一个现场池。工作模式:基于Service-Client
获取到IBinder接口进行IPC的方式有三种:继承Binder类,使用Messenger类,使用AIDL.
Messenger--核心就是Message与Handler来进行线程间通信(ITC)只能串行通信
AIDL 能并行通信。
3.wait和 sleep 的区别
wait是Object的方法,wait是对象锁,锁定方法不让继续执行,当执行notify方法后就会继续执行,
sleep 是Thread的方法,sleep 是使线程睡眠,让出cpu,结束后自动继续执行
4.View和SurfaceView的区别
View基于主线程刷新UI,SurfaceView子线程又可以刷新UI
5.View的绘制原理
View为所有图形控件的基类,View的绘制由3个函数完成
measure,计算视图的大小
layout,提供视图要显示的位置
draw,绘制
6.View的分发机制,滑动冲突
View的事件传递顺序有3个重要的方法,dispatchTouchEvent()是否消耗了本次事件,
onInterceptTouchEvent()是否拦截了本次事件,onTouchEvent()是否处理本次事件,滑动冲突分为同方向滑动冲突,
例如ScrollView和ListView,同方向滑动冲突,可以计算ListView高度而动态设置ListView的高度,ScrollView高度可变。
例如ViewPager和ListView,不同方向滑动冲突,一个是横向滑动一个是竖直滑动,
不同方向滑动可以判断滑动的x,y轴是横向还是竖直滑动,如果判断得到是横向滑动,就拦截ListView的事件,竖则反之。
7.RecyclerView和ListView的区别
缓存上:前者缓存的是View+ViewHolder+flag,不用每次调用findViewById,后者则只是缓存View
刷新数据方面,前者提供了局部刷新,后者则全部刷新
8.说下Activity 的四种启动模式、应用场景
standard 标准模式: 每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在,此模式的 Activity 默认会进入启动它的 Activity 所属的任务栈中;
singleTop 栈顶复用模式: 如果新 Activity 已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时会回调 onNewIntent方法,如果新 Activity 实例已经存在但不在栈顶,那么Activity 依然会被重新创建;
singleTask 栈内复用模式: 只要 Activity 在一个任务栈中存在,那么多次启动此 Activity 都不会重新创建实例,并回调onNewIntent 方法,此模式启动 Activity A,系统首先会寻找是否存在 A 想要的任务栈,如果不存在,就会重新创建一个任务栈,然后把创建好 A 的实例放到栈中;
singleInstance单实例模式: 这是一种加强的 singleTask 模式,具有此种模式的 Activity 只能单独地位于一个任务栈中,且此任务栈中只有唯一一个实例;
9.Android中的几种动画
FrameAnimation(逐帧动画):将多张图片组合起来进行播放,类似于早期电影的工作原理,很多App的loading是采用这种方式。
TweenAnimation(补间动画):是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式。
PropertyAnimation(属性动画):属性动画不再仅仅是一种视觉效果了,而是一种不断地对值进行操作的机制,并将值赋到指定对象的指定属性上,可以是任意对象的任意属性。
10.Android类加载器
在Android开发中,不管是插件化还是组件化,都是基于Android系统的类加载器ClassLoader来设计的。
只不过Android平台上虚拟机运行的是Dex字节码,一种对class文件优化的产物,传统Class文件是一个Java源码文件会生成一个.class文件,
而Android是把所有Class文件进行合并、优化,然后再生成一个最终的class.dex,目的是把不同class文件重复的东西只需保留一份,
在早期的Android应用开发中,如果不对Android应用进行分dex处理,那么最后一个应用的apk只会有一个dex文件。
Android中常用的类加载器有两种,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。
区别在于调用父类构造器时,DexClassLoader多传了一个optimizedDirectory参数,这个目录必须是内部存储路径,用来缓存系统创建的Dex文件。
而PathClassLoader该参数为null,只能加载内部存储目录的Dex文件。所以我们可以用DexClassLoader去加载外部的apk文件,这也是很多插件化技术的基础。
11.IntentService
IntentService是一个抽象类,继承自Service,内部存在一个ServiceHandler(Handler)和HandlerThread(Thread)。
IntentService是处理异步请求的一个类,在IntentService中有一个工作线程(HandlerThread)来处理耗时操作,
启动IntentService的方式和普通的一样,不过当执行完任务之后,IntentService会自动停止。
另外可以多次启动IntentService,每一个耗时操作都会以工作队列的形式在IntentService的onHandleIntent回调中执行,并且每次执行一个工作线程。
IntentService的本质是:封装了一个HandlerThread和Handler的异步框架。
C类 中高级
D类 常考难点