1、类的加载过程,Person person = new Person();为例进行说明
- 因为new用到了Person.class,所以会先找到Person.class,并加载到内存中
- 执行类中的static代码块,如果有的话给Person.class 进行初始化
- 在堆内存中开辟空间分配内存地址
- 在堆内存中建立对象的特有属性,并进行默认初始化
- 对属性进行显示初始化
- 对对象进行构造代码块初始化
- 对对象进行与之相对应的构造函数进行初始化
- 将内存地址赋给栈内存的p变量
2.集合框架,list,map,set都有哪些具体的实现类,区别都是什么
- list是有序存储,可放入重复的元素
- set是无序存储(是按照元素的Hashcode进行排序),不可放入重复的元素
- 在增删查三个方面,list查询比较快(list是数组结构)set删除和插入比较快
- Map适合储存键值对数据
3.ArrayList 和 Hashmap 简单说一些,区别,底层的数据结构
- ArrayList是基于动态数组的数据结构,数据地址是连续,数据的查询比较快,但是数据的插入,删除(除了最后一个数据)效率比较低
- Hashmap是基于哈希表实现的,使用的是动态数组加链表结构,先根据key值的hashCode值,确定数组的位置 然后在放在链表中。负载因子的作用是确定什么时候扩容,Hashmap默认数组长度16 负载因子默认0.75
4.Handler 消息机制
按照代码的习惯说一下流程
1. handler通过sendMessage()方法或者其他的setXXX()方法调用handler中的enqueueMessage()方法向MessageQueue插入一条消息同时会把本事的handler通过msg.target = this传入
2. Looper 是一个死循环,不断的读取MessageQueue中的消息,Looper会调用MessageQueue的next方法获取新消息,next是一个阻塞操作,当没有消息时next方法一直阻塞,导致Looper也一直阻塞
3. 当有消息时会回调handler的dispatchMessage()方法
5. 引起内存泄漏的场景
- 资源对象没关闭
- bitmap对象不在使用时调用recycle()释放
- 构造Adapter时没有使用convertView
- 注册没取消造成的内存泄漏(evenBus,service)
- 单例造成的内存泄漏
- 查找内存泄漏可以使用Android Studio自带的Android Profiler
6. 多线程的使用场景
- App中的耗时操作,比如网络请求,文件操作
- 为了加快App启动 可以把数据存储操作放在线程中
7.常见线程池
- FixThreadPool:只有核心线程,并且数量固定,也不会被回收,所有线程都活动时,新任务会等待执行,优点是响应速度快
- SingleThreadPool:只有一个核心线程,确保所有的任务都在同一线程中顺序操作,因此不需要处理线程同步的问题
- CachedThreadPool:只有非核心线程,最大数量非常大,所有线程都活动时,会为新任务创建新线程,否则会利用空闲线程(60s空闲线程会被回收,所以线程池中有0个线程的可能)处理任务
- ScheduledThreadPool:核心线程数固定,非核心线程(闲这的时候会被回收)数没有数量限制。优点:执行定时任务以及有固定周期重复任务
8. 知道哪些单例模式,写一个线程安全的单例,并分析为什么是线程安全的
- 有饿汉模式,懒汉模式,利用私有的内部工厂类,懒汉模式改良版,静态内部类单例模式
public class Singleton{//懒汉模式
private static Singleton singleton;private Singleton(){} public static synchronized Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; }}
`
public class Singleton{//懒汉模式改良版 目的是为了减少同步开销
private static volatile Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
`
`
public class Singleton{//静态内部类单例模式
private Singleton(){}
public synchronized Singleton getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static final Singleton instance = new Singleton();
}
}`
3.线程安全 是因为有同步线程锁 synchronized;
9. 解释一下HashMap?底部的数据结构?散列表冲突的处理方法,散列表是一个什么样的数据结构?HashMap是采用什么方法处理冲突的?
- HashMap是由数组和链表组合而成的数据结构,存取时都会根据键值计算出“类别”(HashCode),在根据类别定位到数组中的位置并执行操作
- 开放地址法,再哈希法,链地址法,建立一个公共溢出区
- 是根据关键码值直接进行访问的数据结构
- 链地址法
10. 解释一下什么是MVP架构,画出图解,一句话解释MVP和MVC的区别?
- MVP架构是从MVC框架演化而来的 M指model负责业务逻辑和实体模型 V指View 对应于Activity P指presenter 负责View和model之间的交互
- MVC允许Model和View交互 而MVP中Model和View的交互必须由Presenter完成
11. 在使用Handler的时候要注意哪些东西,是否会引起内存泄漏?画一下Handler机制的图解?
- 在子线程使用Handler时必须先调用Looper.prepare()创建Looper;
- 在同一个线程中只能调用一次Looper.prepare()
- 不能再主线程中调用Looper.prepare()
- 当我们在子线程中使用Handler时,如果Handler不在需要发送和接受消息,那么一定要退出子线程的消息轮询。因为Looper.loop()是一个死循环,如果我们不主动结束他,那么它会一直运行,子线程也会一直运行不会结束。
- 会引起内存泄漏,Handler可能会持有外部对象Activity,当Activity关闭时,handler还没执行完,从而引起activity内存泄漏
- handler 引起泄漏的解决方法 使用mHandler.removeCallbacksAndMessages(null)及时清除。使用静态内部类和弱引用
12 采取了哪些措施进行性能优化
- 布局优化 就是尽量减少布局文件的层级
- 使用标签
- 自定义View的时候 绘制优化 尽量减少重复绘制
- 内存泄漏优化
- 响应速度优化 就是避免在主线程中进行耗时操作
- ListView BitMap(对图片进行采样)优化
- 线程优化 避免程序中存在大量的线程,可以采用线程池
- 适当使用弱引用和软引用
- 采用三级缓存
13.引起内存泄漏的原因是什么?以及你是怎么解决的
- 原因是程序向系统申请分配内存空间后 ,在使用完毕后空间未释放,导致一直占用该内存单元
- 回看问题5
14.关于并发理解多少?说几个并发的集合?
15.画图说明View 事件传递机制?并举一个例子阐述
- Activity中事件分发体系 Window -> ViewGroup -> View
- dispatchTouchEvent() onInterceptTouchEvent() onTouchEvent() 三个方法协助
16.intentService作用是什么
- 先说一下service 简单来说,如果用户希望业务出现在后台,而非主界面上,那么Activity肯定没办法满足需求,于是诞生了Service。Service解决了用户可以不在UI界面进行业务操作的问题,如当听音乐时,我们没有必要一直让界面停留在播放界面。在使用Service的时候,一定要注意Service虽然感觉在后台运行,但实际是依附主线程的
- 与service的不同 IntentService是线程处理任务的,自带队列,每个请求都会排队,任务完成自己会调用stopSelf结束,无需我们操心
- 与其他线程的区别,因为intentService是服务的原因,这导致它的优先级比单纯的线程高很多,所以intentService比较适合执行一些高优先级的后台任务,因为它优先等级高不容易被系统杀死
17.String-StringBuffer-StringBuilder区别
- String是字符串常量
- StringBuffer是字符串变量(线程安全)
- StringBuilder是字符串变量(非线程安全)
18.如何判断Activity是否在运行?
`
final Activity activity = progressDialog.getOwnerActivity();
if (activity == null || activity.isDestroyed() || activity.isFinishing()) {
return;
}
`
19.修改SharedPreferences后两种提交方式有什么区别?
commit这种方式很常用,在比较早的SDK版本中就有了,这种提交修改的方式是同步的,会阻塞调用它的线程,并且这个方法会返回boolean值告知保存是否成功(如果不成功,可以做一些补救措施)。
而apply是异步的提交方式,目前Android Studio也会提示大家使用这种方式。
20.SharedPreferences多进程
http://blog.csdn.net/cjh94520/article/details/70880266