面试总结
1. ArrayList 和 LinkedList区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.ArrayList 查询快,因为LinkedList要移动指针。
3.LinedList 增删快,因为ArrayList要移动数据。
2. 关于 hashCoe 和 equals 方法
参考:https://blog.csdn.net/jing_bufferfly/article/details/50868266
==和 equals 的区别 (高频)
区别: 一个是运算符一个是方法
- ==:基本数据类型比较数值是否相等,引用数据类型比较对象地址值是否相等
- equals:用来比较两个对象的内容是否相等。如果没有重写,默认比较地址值
hashCode:
是Object类的一个方法。返回一个离散的int型整数。在集合类操作中使用,为了提高查询速度。(HashMap,HashSet等比较是否为同一个)
如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
如果两个对象不equals,他们的hashcode有可能相等。
如果两个对象hashcode相等,他们不一定equals。
如果两个对象hashcode不相等,他们一定不equals。
重写hashCode()方法时的原则:
- 在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的 hashCode() 方法的返回值必须是相同的一个int值
- 如果两个对象 equals() 返回值为true,则他们的 hashCode() 也必须返回相同的int值
- 如果两个对象 equals() 返回值为false,则他们的 hashCode() 返回值也必须不同
-
为什么需要重写 hashCode() 方法和 equals() 方法
Java中 Object 类中 equals() 方法是用来比较两个引用所指向的内存地址是否一致,我们在定义类时希望两个不同对象的某些属性值相同时就认为他们相同,所以我们要重写equals()方法,按照原则,我们重写了equals()方法,也要重写hashCode()方法,要保证上面所述的原则;所以java中的很多类都重写了这两个方法,例如String类,包装类 -
什么情况下需要重写 hashCode() 方法和 equals() 方法
当我们自定义的一个类,想要把它的实例保存在集合中时,我们就需要重写这两个方法 -
重写 equals() 方法的原则
(1) 使用==操作符判断参数是否是这个对象的引用;
(2) 使用 instance of 操作符判断”参数是否是正确的类型“;
(3) 把参数装换成正确的类型;
(4) 对于参数中的各个域,判断其是否和对象中的域相匹配;
3. 子线程吐司
- Looper.prepare()和Looper.looper();
- runOnUiThread 或 Handler (这样就会将消息投递到主线程的消息队列了感觉不算)
4. Fragment 生命周期
Fragment 和 Activity 生命周期关系图由于Fragment依赖Activity的存在而存在,故在创建(可见)时Activity生命周期中的方法均先于Fragment生命周期中的方法执行;相反,在销毁(不可见)时,是先执行Fragment生命周期中的方法再执行Activity生命周期中的方法。
参考:https://www.cnblogs.com/LangZXG/p/6501839.html
5. onTouch() 和 onTouchEvent() 区别
-
定义不同:
onTouch()方法是 View 的 OnTouchListener 接口中定义的方法。
onTouchEvent() 是 Activity 和 View 中的事件响应的方法。 -
执行优先级不同:
onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。同时 onClickListener 中的 onClick 也不会得到执行,因为 onClick 方法是在 onTouchEvent 的 UP 事件中调用的performClick();
具体见 View 的dispatchTouchEvent
方法:public boolean dispatchTouchEvent(MotionEvent event) { ... if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true; } //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { //1. 先执行 onTouch result = true; } if (!result && onTouchEvent(event)) { //2. 再执行onTouchEvent result = true; } } ... }
6. Service 开启方式
1. start开启服务
- 完整生命周期:onCreate()-->onStartCommand()-->onDestroy()
- startService 开启服务:onCreate()-->onStartCommand()
- stopService 停止服务:ondestroy()
特点:
- 长期运行在后台
- 多次开启多次调用onStartCommand()
2. bind绑定服务
- 完整生命周期:onCreate()-->onBind()-->onUnBind()-->onDestroy()
- bindService 绑定服务:onCreate()-->onBind()
- unbindService 解绑服务:onUnBind()-->onDestroy()
特点:
- 不能长期运行在后台
- 不能被多次绑定,多次绑定无效
- 只能被解绑一次,多次解绑会抛出异常
- 可以调用服务里的方法
- 绑定服务的activity和服务同生同死
两种方式的区别:
- 能不能长期运行在后台
- 能不能调用服务里的方法
3. 混合方式开启服务
完整生命周期:
onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory
-
应用场景:即想服务长期运行在后台,又调用服务里的方法
-
步骤:
- startService开启服务,让服务长期运行在后台
- bindService绑定服务,调用服务里的方法
- unBindService解绑服务
- stopService停止服务
7. RecyclerView 和 ListView 的区别
RecyclerView优点:
- 可以实现横向、竖向、瀑布流效果。
- 支持局部刷新。
- 提供了API来实现 Item 的添加、删除动画效果和 Item 的间隔样式绘制。
- 容易实现拖拽、侧滑删除等功能。
- 默认已经实现了View的复用,不需要类似if(convertView == null)的实现,而且回收机制更加完善
ListView优点:
- addHeaderView(), addFooterView()添加头视图和尾视图。
- 通过”android:divider”设置自定义分割线。
- setOnItemClickListener()和 setOnItemLongClickListener()设置点击事件和长按事件。
在性能上:
如果需要频繁的刷新数据,需要添加动画,局部刷新等,则RecyclerView有较大的优势。
如果只是作为列表展示,则两者区别并不是很大。
Android ListView 与 RecyclerView 对比浅析--缓存机制
RecyclerView 必知必会
8. 图片压缩
1. 质量压缩
主要借助Bitmap中的compress方法实现,给定一个字节大小值如果原文件大于这个值,就一直循环压缩,直到原文件大小等于这个给定的大小。
public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) //format是压缩后的图片的格式、quality的取值范围为[0,100],值越小,经过压缩后图片失真越严重、stream指定压缩的图片输出的地方
特点:
使File形式的图片文件缩小,但是并没有改变图片的宽高,而File格式转换成Bitmap格式进入到内存中时,内存是根据图片的像素数量来给图片分配内存大小的,所以该方式不适用于加载,典型的应用场景是将拍照后的图片压缩后上传到服务器前压缩文件大小,减少服务器资源存储压力。
2. 尺寸压缩
通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩。
主要步骤:
1. 将 BitmapFactory.Options 的 inJustDecodeBounds 参数设置为 true 并加载图片。
2. 从 BitmapFactory.Options 中取出图片的原始宽高信息,他们对于于 outWidth 和 outHeight 参数。
3. 根据采样率的规则并结合目标 View 的所需大小计算出采样率 inSampleSize 。
4. 将 BitmapFactory.Options 的 inJustDecodeBounds 设置为 false,然后重新加载图片。
9. FragmentPagerAdapter 与 FragmentStatePagerAdapter区别
FragmentPagerAdapter:
对于不再需要的 fragment ,FragmentPagerAdapter 会调用事务的 detach(Fragment)
方法来处理它,而非 remove(Fragment)
方法。也就是说,只是销毁了 fragment 的视图,fragment 实例还保留在 FragmentManager 中。
FragmentStatePagerAdapter:
FragmentStatePagerAdapter 会销毁不需要的 fragment。事务提交后,activity 的 FragmentManager 中的 fragment 会被彻底移除。
类名中的 “state” 表明:在销毁 fragment 时,可在 onSaveInstanceState(Bundle)
方法中保存 fragment 的 Bundle 信息,用户切换回来时,保存的实例可用来恢复生产新的 fragment。
简单总结:
FragmentPagerAdapter :仅销毁 fragment 的视图,不销毁内存中的实例。
FragmentStatePagerAdapter:视图和实例都销毁。
使用场景:
1、 FragmentStatePagerAdapter 适用于数据动态性较大、数量比较多、占用内存较多的情况。
2 、FragmentPagerAdapter :适用于那些相对静态、数量也比较少的那种;
10. invalidate() 和 postInvalidate() 区别?
共同点:都是去调用 onDraw() 方法,然后去达到重绘的目的。
区别: invalidate() 用于主线程,postInvalidate() 用于子线程(基于handler)
requeLayout():他跟 invalidate() 相反,他只调用 measure() 和 layout() 过程,不会调用 draw()。
11. hashMap 的缺点
HashMap 底层通过 数组 + 链表 的实现,通过计算hash值实现快速查找的的功能,所以查找效率特别高。
缺点: hash 算法不能保证元素分布平衡性。
- 每次计算hash值都是同一个值 :造成链表中长度多长的问题
- 每次计算hash值都是不同的值 :造成数组会不断的扩容,造成HashMap的容量不断增大。
针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。当链表长度大于 8 时,转换为红黑树。
什么是红黑树
红黑树本质上是一种自平衡二叉查找树,但它在二叉查找树的基础上额外添加了一个标记(颜色),同时具有一定的规则。这些规则使红黑树保证了一种平衡,插入、删除、查找的最坏时间复杂度都为 O(logn)。
12. Object类的equal和hashCode方法重写,为什么?
hashCode 方法