前言
金九银十已过半,不知道大家现在都到哪个阶段了,有没有已经找到心仪的工作的朋友?有没有还没准备好面试在各大平台找资料临时抱佛脚的朋友?或是现在在准备,想要明年金三银四跳槽的朋友?
不管你是现在急切找工作还是找资料备战,我都非常推荐你看看我花2个多月从GitHub,牛客,leetcode上为大家整理收集的2023中大厂Android面试八股文合集,我敢说你看完这份资料,必定能有所收获,不会的能查漏补缺,会的能理解更深刻透彻,在这个竞争压力巨大的环境下拿下一份满意的offer不成问题。
这套题总共分为三十二个模块,分别是:「Java 基础、集合、多线程、虚拟机、反射、泛型、并发编程、Android四大组件、异步任务和消息机制、UI绘制、性能调优、SDN、第三方框架、设计模式、Kotlin、计算机网络、系统启动流程、Binder、Handler、AMS、Dart、Flutter、算法和数据结构、NDK、H.264、H.265.音频编解码、FFmpeg、OpenMax、OpenCV、OpenGL ES」,如下图所示:
面试题展示
一、Java 中深拷贝与浅拷贝的区别?
1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
二、谈谈Error和Exception的区别?
1、Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
2、Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这
种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。
三、什么是反射机制?反射机制的应用场景有哪些?
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。 应用场景:1. 逆向代码,例如反编译2. 与注解相结合的框架,如 Retrofit3. 单纯的反射机制应用框架,例如 EventBus(事件总线)4. 动态生成类框架 例如Gson
四、谈一谈startService和bindService的区别,生命周期以及使用场景?
-
生命周期上的区别
执行startService时,Service会经历onCreate- >onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service 会一直在后台运行,下次调用者再起来仍然可以stopService。执行bindService时,Service会经历onCreate- >onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind- >onDestroy。这里所谓的绑定在一起就是说两者共存亡了。多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind 方法并不会被多次调用,即并不会多次创建服务和绑定服务。 -
调用者如何获取绑定后的Service的方法
onBind回调方法将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。我们需要IBinder对象返回具体的Service对象才能操作,所以说具体的Service对象必须首先实现Binder对象。 -
既使用startService又使用bindService的情况
如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调服务器托管网用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStart 方法便会调用多少次。Service的终止,需要unbindService和服务器托管网stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish的时候)之后,服务才会自动停止。
那么,什么情况下既使用startService,又使用bindService呢?
如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。
另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这样在第一次bindService的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)。 -
本地服务与远程服务
本地服务依附在主进程上,在一定程度上节约了资源。本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应
bindService会方便很多。缺点是主进程被kill后,服务变会终止。远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被kill的是偶,该服务依然在运行。缺点是该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。对于startService来说,不管是本地服务还是远程服务,我们需要做的工作都一样简单。
五、谈谈你对 Activity.runOnUiThread 的理解?
一般是用来将一个runnable绑定到主线程,在runOnUiThread源码里面会判断当前runnable是否是主线程,如果是直接run,如果不是,通过一个默认的空构造函数handler将runnable post 到looper里面,创建构造函数handler,会默认绑定一个主线程的looper对象
六、子线程能否更新UI?为什么?
子线程是不能直接更新UI的
注意这句话,是不能直接更新,不是不能更新(极端情况下可更新)绘制过程要保持同步(否则页面不流畅),而我们的主线程负责绘制ui,极端情况就是,在Activity的onResume(含)之前的生命周期中子线程都可以进行更新ui,也就是onCreate,onStart和onResume,此时主线程的绘制还没开始。
七、你了解 Android 系统启动流程吗?
当按电源键触发开机,首先会从ROM中预定义的地方加载引导程序BootLoader 到 RAM中,并执行BootLoader程序启动Linux Kernel,然后启动用户级别的第一个进程: init 进程。init 进程会解析init.rc脚本做一些初始化工作,包括挂载文件系统创建工作目录以及启动系统服务进程等,其中系统服务进程包括 Zygote、service manager、media 等。在 Zygote中会进一步去启动 system_ server进程,然后在 system_server 进程中会启动AMS、WMS、PMS等服务,等这些服务启动之后,AMS中就会打开Launcher应用的home Activity,最终就看到了手机的“桌面”。
八、Binder有什么优势
性能方面
- 共享内存 0次数据拷贝
- Binder 1次数据拷贝
- Socket/管道/消息队列 2次数据拷贝
稳定性方面
- Binder:基于C/S架构,客户端 (Client) 有什么需求就丢给服务端 (Server) 去完成,架构清晰、职责明确又相互独立,自然稳定性更好
- 共享内存:虽然无需拷贝,但是控制复杂,难以使用
- 从稳定性的角度讲,Binder机制是优于内存共享的。
安全性方面
- 传统的IPC没有任何安全措施,安全依赖上层协议来确保。
- 传统的IPC方法无法获得对方可靠的进程用户ID/进程UI (UID/PID) ,从而无法鉴别对方身份。
- 传统的IPC只能由用户在数据包中填入UID/PID,容易被恶意程序利用。
- 传统的IPC访问接入点是开放的,无法阻止恶意程序通过猜测接收方地址获得连接。
- Binder既支持实名Binder,又支持匿名Binder,安全性高。
九、Binder机制是如何跨进程的
- Binder驱动
- 在内核空间创建一块接收缓存区,
- 实现地址映射:将内核缓存区、接收进程用户空间映射到同一接收缓存区
- 发送进程通过系统调用 (copy_from_user) 将数据发送到内核缓存区。由于内核缓存区和
接收进程用户空间存在映射关系,故相当于也发送了接收进程的用户空间,实现了跨进程通信
十、简述下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()
由于文章篇幅有限,不能将完整的面试题全部展示出来,有需要的小伙伴,可以点击下方课程链接详细了解!!!
https://edu.51cto.com/course/32703.html
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 什么是 Intelligence Enterprise 的 Business network?
Intelligence Enterprise(智能企业)的 Business Network(业务网络)是指企业内部和外部的所有关键业务参与者之间的互动和协作关系。这些参与者包括供应商、客户、合作伙伴、员工等。 Business Network 是 Inte…