前言
现在面试可以说是我们最常挂在嘴边的一个话题了,面试题、面试宝典、面试手册……各种Android面试题一搜一大把,根本看不完,而且现在的面试资料也都还可以,然后就放进了收藏夹吃灰,真到面试的时候,又被面试官问得脚趾扣地。
人都是不满足于现状的,现在15K的薪资,下一份就想拿40K,甚至想冲击年薪百万,但老板又不是慈善家,想拿高薪,就要有与之匹配的能力,保持学习和进步是必须的!
毕竟在当下面试,面试官更在意的是你对某项技术的理解深度,你做了几个项目,CRUD水平有多高这些面试官都不太会关注,随便来个主流技术栈你都能跟面试官对线半小时以上,才是提升你面试通过率的最有效手段。
但话说回来,提升自己技术深度是需要时间的,对于短期突击面试,想要快速找到一份工作的人来说,可以背背我整理的《Android面试题汇总》,里面包含了近几年中大厂的面试真题。无论你是准备面试,还是想要提升技能,这份面试题都是值得珍藏的资料。
废话不多说,直接上面试题
一、谈谈List,Set,Map的区别?
List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的)
二、谈谈ArrayList和LinkedList的区别?
- ArrayList是基于数组的数据结构,LinkedList是基于链表的数据结构。
- ArrayList适用于查询操作,LinkedList适用于插入和删除操作。
三、请简述 LinkedHashMap 的工作原理和使用方式?
查看LinkedHashMap源码发现是继承HashMap实现Map接口。也就是HashMap的方法LinkedMap都有。
LinkHashMap与HashMap的主要区别是:LinkedHashMap是有序的,hashmap是无序的。LinkedHashMap通过维护一个双向链表实现有序,也正是因为要维护这个链表,内存上有更大的开销。
补充下有序和无序:我们说的无序是插入顺序和输出顺序不一致。
补充一下链表结构和顺序结构:线性结构分为顺序结构,和链表结构。
- 顺序结构:在内存中是一块完整有序内存。所以我们在查询的时候时候直接索引index,便可找到要查询的数据,速度非常快,缺点是插入删除慢。有点类似班级排队时(一列纵队),每个人都知道自己在第几个位置。老师只要说第三个位置,那这个同学立马知道老师要找的是自己。这时候要插入一个同学到第二个位置,所以之前第二个位置开始往后的每个同学的位置都要+1。所以比较慢。
- 链表结构:通过结点头记录该结点的上一个结点和下一个下一个结点(就是传统的双链表,单链表就是只记录下一个结点,循环链表就是最后一个结点的下一个结点指向第一个结点)。正是因为这种关系,所以链表结构不需要一块完整的内存,而且插入删除相对快,但是查询相对慢。但是因为要维护结点头,所以内存开销相对大一点。有点类似于班级排队时,每个人虽然不知道自己的位置,但是知道自己前面是谁和后面是谁。当要插入一个同学b时到c前面时,只要c 同学记住自己之前是a,现在换成b.b记住自己前面是a,后面是c。所以想对来说插入很快。删除类似。但是当老师按位置查询时,就要先从第一个开始计数,知道找到老师要找的数字。所以查询慢。
四、如何实现多线程中的同步?
多线程同步和异步不是一回事。几种情况,
- 就是大家说的synchronized 他可以保证原子性,保证多个线程在操作同一方法时只有一个线程可以持有锁,并且操作该方法,
- 就是手动调用读写锁,
- 手动操作线程的wait和notify
- volatile我记得是没有原子性的,他可以保证内存可见性,在多线程的情况下保证每个线程的数据都是最新的
五、谈谈线程阻塞的原因?
1、线程执行了Thread.sleep(int n)方法,线程放弃CPU,睡眠n毫秒然后恢复运行。
2、线程要执行一段同步代码,由于无法获得相关的同步锁,只好进入阻塞状态,等到获得了同步锁,才能恢复运行。
3、线程执行了一个对象的wait()方法,进入阻塞状态,只有等到其他线程执行了该对象的notify()或notifyAll()方法,才可能将其唤醒。
4、线程执行I/O操作或进行远程通信时,会因为等待相关的资源而进入阻塞状态。例如,当线程执行System.in.read()方法时,如果用户没有向控制台输入数据,则该线程会一直等读到了用户的输入数据才从read()方法返回。进行远程通信时,在客户程序中,线程在以下情况可能进入阻塞状态。
5、请求与服务器建立连接时,即当线程执行Socket的带参数的构造方法,或执行S服务器托管网ocket的connect()方法时,会进入阻塞状态,直到连接成功,此线程才从Socket的构造方法或connect()方法返回。
6、线程从Socket的输入流读取数据时,如果没有足够的数据,就会进入阻塞状态,直到读到了足够的数据,或者到 达输入流的末尾,或者出现了异常,才从输入流的read()方 法返回或异常中断。输入流中有多少数据才算足够呢?这要看线程执行的read()方法的类型。int read(); 只要输入流中有一个字节,就算足够。int read(byte[] buff); 只要输入流中的字节数目与参数buff数组的长度相同,就算足够。String readLine(); 只要输入流中邮一行字符串,就算足够。值得注意的是,InputStream类并没有readLine方法,在过滤流BufferedReader类中才有此方法。
7、线程向Socket的输出流写一批数据时,可能会进入阻塞状态,等到输出了所有的数据,或者出现异常,才从输出流的write()方法返回或异常中断。
8、调用Socket的setSoLinger()方法设置了关闭Socket的延迟时间,那么当线程执行Socket的close方法时,会进入阻塞状态,直到底层Socket发送完所有剩余数据,或者超过了setSoLinger()方法设置的延迟时间,才从close()方法返回。
六、请谈谈 Thread 中 run() 与 start()的区别?
run() 和普通的成员方法一样,可以被重复调用。但是如果单独调用 run 方法,则不是在子线程中执行。start()这个方法只能被调用一次。调用这个方法后 程序会启动一个 新的线程来 执行 run 方法。注意 :调用start 后,线程处于可运行状态(并没有运行),一旦得到 cup 时间片,就开始执行run 方法,run 方法结束后,线程则立即终止。
七、synchronized和volatile关键字的区别?
1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则可以使用 在变量、方法、和类级别的volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
3.volatile不会造成线程的阻塞;synchronized可能会造成 线程的阻塞。
4.volatile标记的变量不会被编译器优化;synchronized标 记的变量可以被编译器优化
八、Activity 与 Fragment 之间常见的几种通信方式?
viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递
九、Service如何进行保活?
1、利用系统广播拉活
2、利用系统service拉活
3、利用Native进程拉活 fork进行监控主进程
4、利用native拉活
5、利用JobScheduler机制拉活
6、利用账号同步机制拉活
十、简单介绍下ContentProvider是如何实现数据共享的?
ContentProvider(内容提供者):对外提供了统一的访问数据的接口。
ContentResolver(内容解析者):通过URI的不同来操作不同的ContentProvider中的数据。
ContentObserver(内容观察者):观察特定URI引起的数据库的变化。通过ContentResolver进行注册,观察数据是否发生变化及时通知刷新页面(通过Handler通知主线程更新UI)。
十一、请简述 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()
由于文章篇幅有限,不能将我整理的所有面试题全部展示出来,不过也没关系,我已经将所有的面试题整理成PDF文档了
有需要完整面试题和答案解析的朋友,可以点击下方课程链接详细了解!!!
https://edu.51cto.com/course/32703.html
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
目录 一、前言 二、自定义函数(Function)概述 三、使用场景 四、优缺点 1、数据库中Function的使用优点 2、数据库中Function的使用缺点 五、GaussDB中的Function示例与解析 1、示例一:定义函数为SQL查询 2、示例二:返…