前言
金九银十马上就要到了,又是一年面试季,很多人都准备在这个时候找到一个好一点的工作,我整理了一份阿里、美团、百度、滴滴、腾讯、头条等大厂的面试题合集,其中概括的知识点有,Java基础、Java集合、Java虚拟机、Java多线程、Android四大组件、异步、UI、性能优化、数据结构、算法、音视频、flutter、Kotlin、Framework等模块,共1000多页!!
可以说这份面试题对于 Android开发的朋友来说应该是最全面最完整的面试备战仓库,为了更好地整理每个模块,我也参考了很多网上的优质博文和项目,力求不漏掉每一个知识点,不吹不黑,大家看了之后就知道:金九银十,有他足矣!
废话不多说一起来看面试题吧!!!
一、抽象类与接口的区别?
大体区别如下:
- 抽象类可以提供成员方法的实现细节,而接口中只能存在 public 抽象方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
- 接口中不能含有构造器、静态代码块以及静态方法,而抽象类可以有构造器、静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口;
- 抽象类访问速度比接口速度要快,因为接口需要时间去寻找在类中具体实现的方法;
- 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。
- 接口更多的为了约束类的行为,可用于解耦,而抽象类更加侧重于代码复用。
二、谈谈List,Set,Map的区别?
List中存储的数据是有顺序的,并且值允许重复;Map中存 储的数据是无序的,它的键是不允许重复的,但是值是允 许重复的;Set中存储的数据是无顺序的,并且不允许重 复,但元素在集合中的位置是由元素的hashcode决定,即 位置是固定的(Set集合是根据hashcode来进行数据存储 的,所以位置是固定的,但是这个位置不是用户可以控制 的,所以对于用户来说set中的元素还是无序的)
三、说一下线程的几种状态?
- 第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
- 第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
- 第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
- 第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
- 第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
请简述 Http 与 Https 的区别?
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数
据能加密传输,于是网景公司设计了SSL(Secure SocketsLayer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
最后一点在Android 9.0 如果用http进行传输,需要在application节点下设置android:usesCleartextTraffic=“true”
四、简述下Handler机制的总体原理
- Looper 准备和开启轮循: Looper#prepare()初始化线程独有的 Looper 以及 MessageQueue Looper#loop()开启死循环读取 MessageQueue 中下一个满足执行时间的 Message 尚无 Message 的话,调用
Native 侧的 pollOnce()进入无限等待存在 Message,但执行时间 when 尚未满足的话,调用
pollOnce()时传入剩余时长参数进入有限等待 - Message 发送、入队和出队: Native 侧如果处于无限等待的话:任意线程向 Handler 发送 Message 或 Runnable 后,Message 将按照 when 条件的先后,被插 入 Handler 持有的 Looper 实例所对应的
MessageQueue 中适当的位置。 MessageQueue 发现有合适的 Message 插入后将调用 Native 侧的
wake() 唤醒无限等待的线程。这将促使 MessageQueue 的读取继续进入下一次循环,此刻 Queue 中已有满足条件的
Message 则 出队返回给 Looper Native 侧如果处于有限等待的话:在等待指定时长后 epoll_wait
将返回。线程继续读取 MessageQueue, 此 刻因为时长条件将满足将其出队 Looper 处理Message 的实现: - Looper 得到 Message 后回调 Message 的 callback 属性即 Runnable,或依据 target 属性即 Handler,去执行 Handler 的回调。存在 mCallback属性的话回调 Handler$Callback 反之,回调 handleMessage()
五、Activity 与 Fragment 之间常见的几种通信方式?
viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递
六、对于 Context,你了解多少?
Context也叫上下文,是有关应用程序环境的全局信息的接口。这是一个抽象类, 它允许访问特定于应用程序的资源和类,以及对应用程序级操作的调用,比如启动活动,发送广播和接收意图等;
Activity,Service,Application都是 Context的子类。
Context 的具体实现类是 ContextImpl, 还有一个包装类ContextWrapper, ContextWrapper 的 子 类 有 Service ,Application,ContextThemeWrapper, Activity 又是ContextThemeWrapper 的子类,ContextThemeWrapper 也可以叫 UI Context,跟UI 操作相关的最好使用此类 Context。
ContextWrapper 中有个 mBase,这个 mBase 其实是ContextImpl,它是在Activity, Service, Application 创建时通过attachBaseContext()方法将各自对对应ContextImpl 赋值的。对 context 的操作,最终实现都是在ContextImpl。
对于 startActivity操作
- 当为Activity Context则可直接使用;
- 当为其他Context, 则必须带上FLAG_ACTIVITY_NEW_TASK flags才能使用;因为非 Activitycontext启动 Activity没有 Activity栈,则无法启动,因此需要加开启新的栈;
- 另外UI相关要Activity中使用. getApplication()和getApplicationContext()区别?
- 对于Activity/Service来说,getApplication()和getApplicationContext()的返回值完全相同; 除非厂商修改过接口;
- BroadcastReceiver在onReceive的过程, 能使用getBaseContext().getApplicationContext获取所在Application, 而无法使用getApplication;
- ContentProvider能使用getContext().getApplicationContext()获取所在Application. 绝大多数情况下没有问题, 但是有可能会出现空指针的问题, 情况如下:
当同一个进程有多个apk的情况下, 对于第二个apk是由provider方式拉起的, 前面介绍过provider创建过程并不
会初始化所在application, 此时执行getContext().getApplicationContext()返回的结果便是NULL. 所以对于这种情况要做好判空。
七、请简述一下什么是 Kotlin?它有哪些特性?
kotlin和java一样也是一门jvm语言最后的编译结果都是.class文件,并且可以通过kotlin的.class文件反编译回去java代码,并且封装了许多语法糖,其中我在项目中常用的特性有
- 扩展,(使用非集成的方式 扩张一个类的方法和变量):比方说 px和dp之间的转换 之前可能需要写个Util现在,通过扩展Float的变量 最后调用的时候仅仅是 123.dp这样px转成dp了
- lamdba表达式,函数式编程。 lamdba表达式并不是kotlin 的专利,java中也有,但是有限制, 像setOnClickListener一样, 接口方法只有一个的情况才能调用, 而在kotlin中对接口的lambda也是如此,有这样的限制,但是他更推荐你使用闭包的方式而不是实现匿名接口的方式去实现这样的功能,闭包对lambda没有接口这么多的限制,另外就是函数式编程 在java8中提供了streamApi对集合进行mapsortreduce等等操作,但是对androidapi有限制,为了兼容低版本,几乎不可能使用streamApi
- 判空语法 省略了许多ifxxx==null的写法 也避免了空指针异常aaa?.toString ?: “空空如也” 当aaa为空的时候 它的值被"空空如也"替代
aaa?.let{ it. bbb
}
当aaa不为空时 执行括号内的方法 - 省略了findViewById ,使用kotlin 就可以直接用xml中定义的id 作为变量获取到这个控件,有了这个 butterknife就可以淘汰了,使用databinding也能做到,但是,非常遗憾,databinding的支持非常不好,每次修改视图,都不能及时生成,经常要rebulid才能生成.
- 默认参数 减少方法重载 fun funName(a :Int ,b:Int =123)通过如上写法 实际在java中要定义两个写法 funName(a)和funName(a,b)
- kotlin无疑是android将来语言的趋势,我已经使用kotlin 一年了,不仅App工程中使用,而且封装的组件库也是用kotlin,另外说明,kotlin会是apk大小在混淆后增加几百k.但对于更舒适的代码来说这又算的了什么呢
八、Flutter 中的生命周期
initState() 表示当前 State 将和一个 BuildContext 产生关联,但是此时BuildContext 没有完全装载完成,如果你需要在该方法中获取 BuildContext ,可以 new Future.delayed(constDuration(seconds: 0, (){//context}); 一下。
didChangeDependencies() 在 initState() 之后调用,当 State 对象的依赖关系发生变化时,该方法被调用,初始化时也会调用
deactivate() 当 State 被暂时从视图树中移除时,会调用这个方法,同时页面切换时,也会调用。
dispose() Widget 销毁了,在调用这个方法之前,总会先调用 deactivate()。
didUpdateWidge 当 widget 状态发生变化时,会调用。
通过 StreamBuilder 和 FutureBuilder 我们可以快速使用 Stream 和 Future 快速构建我们的异步控件:
Flutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding ,它主要是通过BindingBase 的子类 GestureBinding 、ServicesBinding 、SchedulerBinding 、PaintingBinding 、SemanticsBinding 、 RendererBinding 、WidgetsBinding 等,通过 mixins 的组合而成的。
Flutter 中的 Dart 的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是 event 外部队列,而 microtask 的优先级又高于event 。
因为 microtask 的优先级又高于 event, 同时会阻塞event 队列,所以如果microtask 太多就可能会对触摸、绘制等外部事件造成阻塞卡顿哦。
Flutter 中存在四大线程,分别为 UI Runner、GPU Runner、IO Runner, Platform Runner (原生主
线程) ,同时在 Flutter 中可以通过 isolate 或者 compute 执行真正的跨线程异步操作。
由于文章篇幅有限,而整理的面试题实在是太多了,在这里我就不过多的展示了,有需要完整面试题和答案解析的朋友可以扫描下方二维码免费领取!!!
![](https://i-blog.csdnimg.cn/blog_migrate/b3ded40307252c070a2e5673419b9b5d.jpeg)
第一章 Java方面
- Java基础部分
- Java集合
- Java多线程
- Java虚拟机
第二章 Android方面
- Android四大组件相关
- Android异步任务和消息机制
- Android UI绘制相关
- Android性能调优相关
- Android中的IPC
- Android系统SDK相关
- 第三方框架分析
- 综合技术
- 数据结构方面
- 设计模式
- 计算机网络方面
- Kotlin方面
第三章 音视频开发高频面试题
- 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
- 怎么做到直播秒开优化?
- 直方图在图像处理里面最重要的作用是什么?
- 数字图像滤波有哪些方法?
- 图像可以提取的特征有哪些?
- 衡量图像重建好坏的标准有哪些?怎样计算?
- …
第四章 Flutter高频面试题
- Dart部分
- Flutter部分
第五章 算法高频面试题
- 如何高效寻找素数
- 如何运用二分查找算法
- 如何高效解决雨水问题
- 如何去除有序数组的重复元素
- 如何高效进行模幂运算
- 如何寻找最长回文子串
- …
第六章 Andrio Framework方面
- 系统启动流程面试题解析
- Binder面试题解析
- Handler面试题解析
- AMS面试题解析
第七章 企业常见174道面试题
- SD卡
- Android的数据存储方式
- Broadcast Receiver
- sp频繁操作会有什么后果?sp能存多少数据?
- dvm与jvm的区别
- ART
- Activity的生命周期
- Application能不能启动Activity
- …
结语
希望这份面试题,能帮助大家把握住机会,找到自己心仪的工作!!