- java 基本数据类型,分别占几个字节
- hashcode 和 equals 作用
- == 和 equals 区别
- final到底修饰了什么
- hashMap 原理
- hashSet 原理
- 动态代理的使用和原理,使用场景如何?
- 内部类和静态内部类,有什么特性和用处?
- Compareable 和 Compartor 区别
- ArrayList 和 LinkedList 区别,优缺点
- 反射
- 四大组件作用和理解
- 安卓启动模式以及内部堆栈
- Activity启动流程
- Fragment 生命周期和使用
- Fragment 懒加载
- 理解View,Activity,Window三者关系
- View事件传递机制
- 自定义View的流程
- 点击事件分发流程
- View.post为什么能拿到宽高
- Handler机制
- RecyclerView相关
- Bitmap 和 Drawable
- dp,px,dentify关系,如何适配不同分辨率
- Invalidate和postInvalidate和requestLayout应用场景
- 内存泄露发生及处理
- 反射的作用和原理
- 注解的作用和原理
- 线程和进程(结合安卓实例说明ActivityA和ActivityB是否在一个线程中?)
- 线程间同步(例如先执行A,在执行B或者AB都执行一半后,再执行后一半,要求先做完的等后做完的)
- hashcode和equal的区别
- 安卓的消息循环机制
- 单例模式写法
- ANR出现场景和原理
- 什么是泛型擦除
- 进程间通讯方式
- AIDL使用和原理
- Error和Exception区别以及Throwable
- LruCache如何实现?为什么用LinkedHashmap?
- 如何捕获全局异常
- Service使用?bind和start
- Service实现下载如何更新UI
- 属性动画源码
- 大图加载
- MVC & MVP & MVVM
- AsyncTask和IntentService和HandlerThread
- Context的种类和使用
- 热修复
- 插件化
- UI适配
- 优化相关
- JNIEnv 和 JavaVM?
地址比较用 == ,内容比较用 equals
注意的是 Object 的 equals 方法是 == 实现的,也就是说 equals 的具体实现依赖于类的创造者
final 修饰符作用与地址,类似于 == 1.final 修饰8大基本类型,则该引用不能重新赋值 2.final 修饰类类型,则该引用的地址是死的,即不能再引用其他的类,但是该类本身是可以修改的,比如修改类的成员属性是OK的
hashmap 的主干是 Node 数组,Node 是 实现了 Map.Entry 的内部类,其包含了 hash,key,value,next 四个成员,Node 正式实现单链表的关键
假设 hashmap 保有一个长度为 2^n(必须是2的幂) 的 Node 数组,put 的时候首先计算 key 的 hash 值,在根据 hash 值的后 n 位得出存贮的下标,如果没有冲突就完事,有冲突则采取链表法解决冲突,即 Node 数组每一位可以不存,存一个 Node 类,存一个 Node 链表。
那长度为什么要是2^n呢?因为这样保证了 hash 碰撞率低。代码中有这样一句 hash & (length - 1)
,化成二进制即 XXXX & 1111 (n=4,长度为16),保证了后 n 位都是 1,方便 & 操作,这样 n 位数可以表示 2^n 个数,与数组长度吻合
hashset 虽然是 Collection 的子类,但它的实现确实借助 HashMap:
public HashSet() { map = new HashMap<>(); }
利用 HashMap 的 key 不可重复的特性,HashSet 把值放入 HashMap 的 key 中,而 value 则放入 private static final Object PRESENT = new Object();
1.非静态内部类可以访问外部类所有属性和方法,包括 private 修饰的(包含外部类引用),而静态内部类不可以访问除static外的外部类任何属性或方法(不包含外部类引用)
2.非静态内部类隐式保有外部类的对象(OutClass.new InnerClass 可见创建非静态内部类一定要先创建外部类),而静态内部类与外部类没有关联
3,非静态内部类中不能有任何 static 修饰的东西,而静态内部类可以拥有一切属性和方法
4.另外,匿名内部类内部用到外部类属性需加 final
5.内部类 + 接口 可以实现多继承,比如:
class Father{
public String powful = "市长";
}
class Mother{
public String wealthy = "一百万";
}
class Son{
class From_Father extends Father{
}
class From_Mother extends Mother{
}
void showFamily(){
Log.d("lpy","I'm powerful " + new From_Father().powful);
Log.d("lpy","I'm rich " + new From_Mother().wealthy);
}
}
进程:资源分配的最小单位
线程:程序执行的最小单位
1.多进程的程序健壮,一个进程死了,不影响其他进程,而一个线程死了,程序就挂了
2.进程切换花销巨大,线程则更轻便
对于安卓,默认所有组件都在主线程中运行,但是可以通过修改 manifest 中 等四大组件标签的 android:process 属性来使其运行在指定的线程中,不仅如此, 标签也支持此属性
系统内存不足时,可能会强行关闭某些进程,其资源也会随之销毁,优先级如下:
- 前台进程 用户当前操作所必须的进程,即满足一下任一条件即视为前台进程:
- 进程正在托管用户与之交互的 Activity
LruCache 内部使用 LinkedHashMap 存取数据,使用时只需要新建一个类 extends LruCache 即可,构造函数需要传入缓存的最大值
每次 put 时,会调用 getSize 函数计算 put 的 item 的实际大小,LruCache 会根据 item 大小进行判断是否添加到缓存中抑或是直接丢掉,每次 put 会调用 evict 函数弹出最近最少未使用的元素,也就实现了 LruCache 的核心思想。
被弹出的元素会回调 onItemEvicted 函数
如果想改变缓存大小,使用 setSizeMultiplier 函数传入一个 float 型的 multiplier,最终调用了 Math.round(initialMaxSize * multiplier) 和 evict 函数实现了改变缓存大小
那为什么要使用 LinkedHashMap 呢?
因为 LinkedHashMap 可以极其方便的实现 最近最少未使用 的算法
玄机就在 LinkedHashMap 的构造函数里:
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
accessOrder 为 true 则是 access-order,访问顺序,你每次 put 或者 get 都让该元素重新排列在链表末端,也就是说链表头部的元素就是 最近最少未使用的元素啦
accessOrder 为 false 则是 insertion-order,插入顺序,也就是你插入时的顺序就是最终的顺序
JNIEnv 是线程相关的,表示该线程的 java 运行环境,也就是说,jni 想调用 java 的东西,就需要这个 JNIEnv 来帮忙,JNIEnv 可以有很多个 JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局仅仅有一个
dpi : dots per inch,在安卓中,表示对角线上有多少个像素
density : 屏幕像素密度, dp * density = px , density = dpi / 160
推荐今日头条的适配方案,动态修改 denstity 的值,举例说明:
设计图 1920 px * 1080 px ,宽度经计算为 300dp ,我们手机的宽度为 Xpx 以及对应的 Ydp,那么我们想 X = 300dp * dendity,那么 density = 手机实际物理像素 / 设计图宽度的dp值,这样就完成了适配
但是,这个方案会影响第三方库中的 UI 设计,导致其控件尺寸不可避免的放大或缩小