2018面试总结
[toc]
2018面试总结
重载以及重写的区别:
重写(override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不可以改变。
规则
- 参数列表必须与被重写方法相同
- 返回类型必须与被重写方法相同
- 访问权限不能比父类中被重写的方法的访问权限更低
- 父类的成员方法只能被它的子类 重写
- 声明为final的方法不能被重写
- 声明为static的方法不能被重写,但是能够被再次声明
- 子类和父类不在同一个包中,那么子类可以重写父类所有的方法,除了声明为final和private的方法之外
- 子类和父类不在同一个包中,那么子类只能够重写父类的public和protected的非final方法
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不可以被重写
- 如果不能继承一个方法,则不能重写这个方法。
重载(Overload)
重载是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
规则
- 被重载得方法必须改变参数列表(个数或者类型)
- 被重载得方法可以改变返回类型
- 被重载得方法可以改变访问修饰符
- 被重载得方法可以声明或者更广得检查异常
- 方法能够在同一个类中或者在一个子类中被重载
- 无法以返回值类型作为重载函数的区分标准
区别点 | 重载overload | 重写override |
---|---|---|
参数列表 | 必须修改 | 不可以修改 |
返回类型 | 可以修改 | 不可以修改 |
异常 | 可以修改 | 可以减少或者删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
发生时期 | 编译期(在编译期就可以根据参数类型来选择运行哪个方法) | 运行期(编译期在编译期并不知道要运行哪个方法,只有在代码运行的时候jvm才可以做出决定) |
Service以及IntentService的区别
区别点 | Service | IntentService |
---|---|---|
运行线程 | 依附于主线程 | 自身内部新开了线程 |
是否是完整的生命周期 | 是 | 是 |
IntentService继承于Service,所以它有service的所有特性,也包括service的生命周期,与Service不同的是,IntentService在执行oncreate的时候,内部开辟了一个新线程,去执行所要执行的耗时操作,而普通的service是依赖于应用的主线程的,所以service事实上并不能做耗时操作(不开异步线程的话)
具体参考参考
区别点 | Service | IntentService |
---|---|---|
运行线程 | 依附于主线程 | 自身内部新开了线程 |
是否是完整的生命周期 | 是 | 是 |
线程间的通讯方式
- runOnUiThread(Runnable)
- View.postDelay(Runnable , long)/new Handler().postDelayed(Runnable)
- Message/Handler
- AsyncTask
进程间通信的方式
- Bundle/Intent传递数据
可传递基本类型,String,实现了Serializable或Parcellable接口的数据结构。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代码量少(仅一句),但I/O开销较大,一般用于输出到磁盘或网卡;后者实现代码多,效率高,一般用户内存间序列化和反序列化传输。
- 文件共享:
对同一个文件先后写读,从而实现传输,Linux机制下,可以对文件并发写,所以要注意同步。顺便一提,Windows下不支持并发读或写。
- Messenger:
Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
- AIDL:
AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。通过编写aidl文件来设计想要暴露的接口,编译后会自动生成响应的java文件,服务器将接口的具体实现写在Stub中,用iBinder对象传递给客户端,客户端bindService的时候,用asInterface的形式将iBinder还原成接口,再调用其中的方法。
- ContentProvider:
系统四大组件之一,底层也是Binder实现,主要用来为其他APP提供数据,可以说天生就是为进程通信而生的。自己实现一个ContentProvider需要实现6个方法,其中onCreate是主线程中回调的,其他方法是运行在Binder之中的。自定义的ContentProvider注册时要提供authorities属性,应用需要访问的时候将属性包装成Uri.parse(“content://authorities”)。还可以设置permission,readPermission,writePermission来设置权限。 ContentProvider有query,delete,insert等方法,看起来貌似是一个数据库管理类,但其实可以用文件,内存数据等等一切来充当数据源,query返回的是一个Cursor,可以自定义继承AbstractCursor的类来实现。
- Socket:
学过计算机网络的对Socket不陌生,所以不需要详细讲述。只需要注意,Android不允许在主线程中请求网络,而且请求网络必须要注意声明相应的permission。然后,在服务器中定义ServerSocket来监听端口,客户端使用Socket来请求端口,连通后就可以进行通信。
- 广播(Broadcast)
广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。 在应用程序中发送广播比较简单。只需要调用sendBroadcast方法即可。该方法需要一个Intent对象。通过Intent对象可以发送需要广播的数据。
ArrayList以及LinkList的区别
相同点
- 都是List接口的实现类,所以都实现了List的所有未实现的方法(面向接口开发,List->Collection->Iterable)
不同点
- ArrayList实现了List接口,是以数组的形式来进行实现的,所以可以很方便地使用索引的方法来快速定位对象的位置(所以对于要求快速取得对象的需求,用ArrayList更加方便)
- LinkedList是使用链表的方式来进行实现的,他本身有自己的对应方法:addFirst(),addLast()等等,由于是采用链表的方式实现的,所以在insert,remove的时候要比ArrayList方便快捷得多,适合用来实现Stack(堆栈),Queue(队列)。
问题
- 在删除和插入数据的时候,为什么ArrayList的效率会比较低呢?
答:因为ArrayList是使用数组实现的,如果要从数组中插入或者删除一个对象,需要移动后半部分的元素,从而需要重新调整索引顺序,而这个需要耗费一定时间,所以速度上就慢了很多;而LinkedList是使用链表实现的,如果要从链表中删除或者插入一个数据对象,只需要改变前后对象的引用就可以了。
数组,ArrayList的区别
相同点
ArrayList是基于数组实现的,所以理论上ArrayList包含了数组的所有方法
不同点
- 数组可以包含基本数据类型和对象类型,ArrayList只能包含对象类型
- 数组的大小是固定的,而ArrayList是可以扩容的(扩容1.5倍)---> 在添加数据的时候,ArrayList会去检查是否超过了他的存储临界点,如果是超过了,那么他会自我扩容:创建新的内部数组(长度为老数组的1.5倍),把老的数据copy进去,再销毁老的数组。
- ArrayList通过拓展api提供了更多的方便api供开发者使用
- 对于基本数据类型,ArrayList使用自动封箱来减少编码工作量,但是,如果数据的长度是固定的话,这种方式比数组更慢(因为数据的长度已经固定了,数组的大小也可以确定了)
ArrayList和Vector的区别
同步性
Vector是线程安全的(同步的),而ArrayList是线程不安全的(不同步的)
操作
Vector支持多线程操作,所以在效率上比不上ArrayList
数据增长
ArrayList和Vector都有一个初始的容量大小,当存储进去它们里面的元素个数超出容量的时候,就需要增加ArrayList和Vector的存储空间,每次增加存储空间的时候不是只增加一个存储单元,是增加多个存储单元。
Vector默认增加原来的一倍,ArrayList默认增加原来的0.5倍。
Vector可以由我们自己来设置增长的大小,ArrayList没有提供相关的方法。
Android事件分发的原理
具体概况
将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程
参与角色
类型 | 简介 | 备注 |
---|---|---|
Activity | 控制生命周期&处理事件(Controller) | 统筹视图的添加&显示;通过其他回调方法与window,view进行交互 |
View | 所有UI组件的基类 | 基本上所有的视图都是继承自View |
ViewGroup | 一组View的集合 | 其本身也是View的子类;是安卓所有布局的父类;它实质上也是一个View,但是比普通的View多了包含子View&定义布局参数的功能 |
事件类型
方法 | 作用 | 调用时刻 |
---|---|---|
dispatchTouchEvent() | 分发&传递点击事件 | 当事件能够传递给当前View的时候,该方法就会被调用 |
onInterceptTouchEvent() | 判断是否拦截了某个事件(该方法只存在于ViewGroup中,普通的View没有这个方法) | 在ViewGroup的dispatchTouchEvent()中被调用 |
onTouchEvent() | 处理点击事件 | 在dispatchTouchEvent()中被调用 |
事件流程
偷来的示意图equals以及hashcode
相同点
equals以及hashcode在java中的作用都是一样的,都是用于判断2个对象是否一致。
不同点
方法 | 好处 | 坏处 |
---|---|---|
equals | 比较全面,比较复杂 | 效率比较低 |
hashcode | 单纯生成一个hashcode进行比较即可,效率更高 | 不同对象可能会生成一样的hashcode,所以这个单纯的比较并不是特别可靠 |
解决方案
由于他们2个分别存在有这样那样的问题,单纯用equals比较效率太低,单纯用hashcode去比较的话准确率太低,所以我们得出一个解决方案:
用这2个一起去比较!综合起来使用:需要比较的时候,我们先用hashCode()比较,如果hashCode()不一致了,那么这2个对象肯定不一致了,便无须进行equals()的比较了;反之即再进行equals()的比较,这样在保证稳定准确的前提下提高了效率。
这也是为什么我们重写了equals方法就一定要重写另外一个hashcode方法的原因了。