一个安卓开发的面试整理

前言:

面试的时候,基本上是拿着简历就开聊,所以你脑子有代码,也拿不出来展示,只能简单的概括或者表述下基本实现思路,我称之为把书读薄。

Android应用开发几年工作经验,面试的公司不少,也当过面试官,写这篇文章一方面用来梳理自己的知识体系,也为了不是做安卓的面试官提供一些问题用来询问应聘者--(曾经待过一个公司由后端架构师来面试安卓,结果这哥们拿着电脑从网上找问题去问他,看答案和回答的一不一样来评价)

面试的思路是从一个点开始向下挖,看知识的深度怎么样,回答不了或者没有什么拓展了,就换一个方向,最后评审知识的广度,大概就可以打分评级了。

最后我也不是大神,大家可以自己尝试回答一下这些问题,我回答错误的地方欢迎联系我修改,不甚感激!

一,从Java基础开始

思路写在前面:由基础知识到线程安全问题,再引导到对象组成,引出对象头,聊聊volatile,然后线程池,回到之前对象头里的gc标记,然后gc算法,注解,最后设计模式,其实后面可以从gc再引导到安卓的内存泄漏然后,性能优化,这是安卓部分的问题了

1.1Java三大特性:

封装继承多态(这三个作为面试官,不知道问啥,由大家来补充,后面更新);

1.2你用到了哪些集合:

list,set,map;

ArrayList和LinkedList区别:ArrayList是由数组(array)实现的,LinkedList是基于链表(Link)的数据结构;array可以通过下标访问元素,在查找或者删除某个元素的时候更快,但是数组是固定容量,所以增加元素的时候有可能不如link;

1.3为什么ArrayList无参构造函数初始为10每次扩容1.5倍:

早期的jdk1.8里面,ArrayList在构造函数里就直接初始化为一个容量为10的数组,后面的jdk是空数组,在第一次调用add函数的时候初始化数组容量为一个default常量的值,固定为10,或者add传入的size+1(判断哪个大);至于为什么是1.5倍,是因为扩容的算法是新容量等于旧容量和旧容量右移1位的和,用位运算是因为它比取模运算效率要高很多。

1.4hashmap的初始容量:

hashmap的初始容量是16,每次扩容1倍,容量到3/4的时候扩容,为什么这样设计,大家来回答!

1.5用过哪些线程安全的容器:

ConcurrentHashMap,Hashtable,BlockingQueue,Vector等等。

1.5为什么还要设计ConcurrentHashMap:

以前的线程安全实现方法是给所有的方法加锁,而ConcurrentHashMap是分段锁(到这里差不多了,可以再聊聊这个原理,或者这样做有什么区别)

1.6简单说说锁的原理:

Java中给对象加锁,其实在底层上是修改了对象头里一个标记位,如果有一个线程访问该对象时,先判断对象头里的标记位,如果是1说明有锁并且有其他线程正在访问需要等待,访问线程执行完代码,释放锁(修改标记位为0),由下一个线程获得锁(修改为1)并进入同步块执行代码,指令上来说是通过lock和unlock实现对锁的控制。

1.7java对象在内存中存储的布局是怎样的:

java对象在内存中由三部分组成:head(对象头),data(实例数据),padding(对齐填充),这里有点深了,主要是为了引出对象头,回答不了可以跳过直接聊对象头

1.8说说对象头里面有什么:对象头包括三部分信息:

Mark Word(标记),klass Word(指向类的指针),array length(数组长度)(只有数组对象才有)

1.9说说mark word里面有什么:

是否有锁啊,锁状态啊(分代),还有gc标记;里面的偏量锁,轻量级锁,重量级锁,用的太少就不说了。

1.10说说volatile:

用来修饰变量的,目的是多个线程修改变量的时候,其他线程能同时知晓修改之后的值(这就是可见性),cpu指令执行的时候通常是一条指令执行完成后才执行下一条,但是有些指令执行需要一定耗时的时候,其他指令就会插入进来,指令执行顺序就会发生改变,volatile的原理是通过内存屏障的规则禁止重排序(这就是有序性);但是volatile只能保证单次读写的执行顺序,比如i++,是读i的值加1,再写给i,本质上是读、写两次操作,所以同时执行百万次i++后,i的值并不是一百万,所以volatile不能保证完全的原子性,只能保证单次的读/写操作具有原子性。

1.11那如何保证原子性:

加锁跟使用Atomic类

1.12Atomic是如何保证原子性的呢:

CAS:底层采用CP

U原子指令或锁机制来实现,多数情况采用cpu原子指令,通过硬件级别的操作来完成对一个内存位置的读写比较。

到这里就相当厉害了,聊不下去了,回到对象头里的gc。

1.13说说GC的两种算法:

引用计数:对象头里存储该对象被多少个其他实例对象引用的次数,如果为0,标记为可回收;

根索引:从gcroot开始遍历引用树,如果没有在树的范围内,说明没有引用,标记为可回收。

那gcroot有哪些:静态属性引用的对象,或者静态类,所有被同步锁持有的对象,

下面是复制过来的:

1、虚拟机栈中引用的对象;

2、本地方法栈内JNI (通常说的本地native方法)引用的对象;

3、方法区中类静态属性引用的对象;

4、方法区中常量引用的对象;

5、所有被同步锁synchroni zed持有的对象;

6、Java虚拟机内部的引用;

7、反映j ava虛拟机内部情况的JMXBean、 JVMTI中注册的回调、本地代码缓存等。

1.14说说dalvik虚拟机和art虚拟机在gc上的区别:

安卓从5.0以后用art替换dalvik虚拟机,gc上art只暂停一次,dalvik需要暂停2次;并发复制,art也减少了内存碎片

下面是复制的:art的gc优化:

只有一次GC暂停(Dalvik需要两次)

并发复制,可减少后台内存使用和碎片

GC暂停的时间不受堆大小影响

在清理最近分配的短时对象这种特殊情况中,回收器的总GC时间更短

优化了垃圾回收的工效,能够更加及时地进行并行垃圾回收,这使得GC_FOR_ALLOC事件在典型用例中极为罕见

1.15jvm的结构知道吗:

堆,方法区,程序计数器,本地方法栈

gc里面自己的话有点少,我看看怎么规划为自己和别人都容易理解的话语,后面再修改,这条线先暂停,跳到注解问题(这里应该由多线程跳到线程池到携程再到设计模式,我还没想好问题,后面更新)。

1.16自定义过注解吗,说说注解的三个保留级别:

runtime(运行时),class(字节码),source(源码)

1.17说说这三个保留级别具体的作用并举例:

最简单的runtime:反射:在程序运行时,通过反射动态获取注解和修饰的元素,拿到参数进行逻辑判断,这个栗子比较多;

class:字节码增强:具体就是用来做热修复,修改class,好多热修复工具就用到了这个

拷贝内容:在编译出class后,通过修改class数据以实现修改代码逻辑目的,对于是否需求修改的区分或者修改为不同逻辑的判断可以使用注解;

在不改变Java源代码的情况下,通过修改字节码文件的方式来增强Java程序的功能(这个比较好理解)

source:APT(Annotation Processing Tool),用来在编译时获取注解和注解声明的类,包括类里的成员信息,获取之后用来干嘛呢,一般用来生成额外的辅助类;

举个栗子:databinding,xml里面必须用固定格式:layou标签下包含data标签,然后写ui标签;这里的xml在编译时会生成另外两个xml文件,分别对应ui和data,这两个文件就是用apt写的。

1.18线程池用过吗,说说有几种创建方式

这里必须说用过,无论是retrofit,glide,还是携程,其实内部都用到了线程池,retrofit和glide差不多,每次请求都是一个runnable,然后丢到线程池去执行,如果回答不了解,直接就pass了。

至于创建方式,网上各有说法,我理解的其实就两种或者说就一种:1,通过 ThreadPoolExecutor 创建的线程池;2,通过 Executors 创建的线程池。Executors其实是直接使用,通过静态方法创建线程池,无论是single,cash,fix线程池最后还是通过 ThreadPoolExecutor 创建线程池,设置自己的核心线程数,最多线程数,缓存队列,比如single核心线程数就是1。

1.19那说说携程里的线程池,你理解的携程

携程在我眼中有两个好处,1,携程比线程更轻量级一点;2,携程用同步的方式写出异步的代码,比rxandroid更加优雅,在携程体里的代码,有suspend关键字修饰的函数,执行在异步,执行完成后又回到原线程执行下一句代码,这个suspend修饰的函数,其实就是运行在另一个线程,可以理解为这里创建了一个runnable,run里的内容就是suspend函数,然后通过线程池来运行。

这里有调度器问题。

这里涉及到一个问题,线程池有核心线程数,那携程的核心线程数又是多少呢,

其实携程的核心线程数是变化的,根据suspend函数里的运算是io密集型,还是cpu密集型,一般是设备的cpu核心数(八核,或者十六核听着就很熟悉对吧)

先写到这里,后面再更新携程。

Android部分,大概思路是从handler开始,到应用启动流程,到事件分发,自定义view,三方框架,动态代理等等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值