获得徽章 5
- HashMap细节补充
0.基础概念
负载因子:SIZE/CAPACITY 代表容量百分比
哈希碰撞:不同的原始值经过哈希运算计算Index时在相同的位置
解决:链地址法 JDK做法 数组中存储链表 重复了进行头插
哈希计算 H(Key) 常见的有MD4 MD5 SHA-1 好的哈希算法一定是冲突少 分布均匀
哈希映射 将哈希计算后的值 转化为数组索引 JDK中是将哈希值与 (数组容量-1)进行与运算得到(也有除容量取余)
1.扩容为什么是2的幂次
因为通过哈希算法计算的哈希值需要与 (容量-1)做与运算 得到index索引位置
2的幂次-1 都是类似 1000.. -1 = 01111... 都是尾数为1 便于进行与运算 区分结果
如果尾数都为0 那么结果肯定为0 导致可能产生的结果数少 碰撞多 根据策略进行再哈希 或者下标+1 查询效率低
2.哈希表元素插入链表中时用的是头插还是尾插
JDK1.8之前是采用头插 将整个链表放在新结点之后
但会有隐患 操作整个链表 在扩容时会造成指针指向变化 可能形成环形链表
JDK1.8后采取的是尾插法 不会形成环形链表 但可能会造成扩容时指针指向位置的变化 造成错位
JDK1.8优化了树的结构 在容量超过阈值转为红黑树 红黑树是二叉查找树的优化 最主要的作用是保证深度在任何情况下保证相对小
维持红黑树的规则 保证了从根到叶子的最长路径不会超过最短路径的两倍
为了保持树的结构 应该将新节点纳入红黑树中 进行自平衡
3.HashMap HashTable ConcurrentHashMap区别,内部数据结构 扩容机制 存取方式
HashMap底层数组+链表 KV可以为NULL 线程不安全 扩容*2 重新对元素进行哈希计算位置
HashTable底层也是数组+链表 在其方法上加入了synchronized 保证线程安全 但效率降低 KV不能为NULL
ConcurrentHashMap是这两者优点的集中和优化
底层采用分段锁 默认将Map分为16段 提供相同的线程安全 最重要的是锁分离技术
hashtable是每次锁住整个哈希表让线程独占
分段锁允许多个线程锁住不同的段 提高了并发效率
对多段分配阈值 左移扩容翻倍展开评论点赞 - 手写冒泡排序?如何优化?
冒泡排序是一种交换排序 每轮排序过后 选出其中的一个最大值
剩下的数继续做相同的比较并排序 时间复杂度为O(n^2) 空间复杂度为O(1)
1.用变量记录每轮交换次数 如果一轮遍历完次数为0 表示元素已经有序 退出循环
2.如果一个数组 一轮交换后 最后发生交换的位置为N 代表N之后的序列已经有序
只用对0~N-1进行排序即可
优化过后可以在对内有序对数比较多的序列 减少计算次数展开评论点赞 - LruCache和DiskLruCache底层实现
LRU概念-最近最少使用 将访问的元素根据访问的顺序 进行排序
LruCache和DiskLruCache底层均为LinkedHashMap 是一个由包含KV的结点形成的双向链表
按照进入的顺序排列 当进入的元素在链表里有重复 会将这个元素调到链头表示访问频度高 当超过空间阈值时 会首先淘汰最近最少使用的元素
DiskLru相比于Lru来说 更注重于对文件的读写 和文件操作的保护
LruCache因为其特性会出现在使用中有元素被淘汰 而在业务场景中有时候需要被淘汰的元素 我们可以将其淘汰的元素 存储起来保存在队列中 避免这种情况展开评论点赞 - ConcurrentHashMap
提供线程安全的HashMap
不同于HashTable每个方法加synchronized 提高了多线程的安全又提高并发效率
其引入了分段锁概念 将一个大的Map划分为多个线程安全的Segment段 默认分为16段 并且16段分别持有不同的锁
再根据hashcode进行划分,Segement内部有数组存储KV展开评论点赞 - APK大小优化
1.图片无损压缩 转换WebP
2.代码混淆 资源混淆
3.第三方加固dex合并
4.Lint检测删除无用资源
5.SO库精简(基本上armable的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,如果没有这方面的要求,可以精简。)
6.插件化 懒加载展开评论点赞 - APP冷启动优化?
1.异步加载SDK IntentService
2.初始化操作 懒加载
3.布局轻量化
4.如果首屏图是长驻的可以设置为背景
5.退出APP改为切换后台 下次进入APP热启动展开评论点赞 - 请简述一次http网络请求的过程?
客户端发起连接
请求DNS服务器 解析域名拿到服务器IP
向服务器进行TCP连接 三次挥手
客户端拼装请求报文并发送
服务器接收到请求取内容 进行业务处理 得到结果组装响应报文发送回客户端
断开连接 四次挥手展开评论点赞 - 线程的状态
当new Thread新建线程时 线程为NEW 新建状态
接着线程会进入锁池竞争获取锁 如果成功获取锁会进入就绪状态
获取失败
进入就绪状态的线程 会等待CPU分配时间片 之后进入运行状态 执行任务
如果线程在运行中被调用了sleep睡眠 中断join(放弃CPU占用而停止运行的情况)都会进入阻塞状态加入到阻塞队列中 等待唤醒或者时间到
释放锁的进锁池重新获取
保留锁的进入就绪状态 等待CPU时间片
如果调用的是wait方法 线程会进入等待状态(需要外部唤醒notify) 加入等待池 唤醒之后再去锁池竞争锁
执行完毕后进入死亡状态展开评论点赞 - 电量优化
GPS
精确度不高的需求 可以使用WIFI定位或基站定位
如果使用GPS 需要缓存数据 并定时刷新
多进程和后台服务
按需启动 用完即销
减少APP内部请求数和数据量
连接需要握手或者挥手 消耗电量资源
网络请求工具一般都会有重连机制 失败后重连次数需要限制展开评论点赞