本人近况
年底裁人了,一年半没准备面试了,之前换也是内推的,在这个寒冬的冬天还经历此遭,偏偏还赶上裁员
心态早已爆炸,大的环境不好,各位且干且珍惜....
记录下最近的面试经历,整理下让自己不断进步!
题外话
我不知道一个人人性究竟可以坏到什么程度,但是我最近亲身经历的确实是这样,我一个安心想做技术的人跟你TMD HR部门的八竿子打不着,又何苦为难我呢? 之前有个公司的薪酬绩效主管,邵X,只因为我在大会上顶撞了她一个问题,一味着揪着我的把柄不放,甚至特么的为了少给我一个季度的绩效不允许提前转正,真的是坏透了,可能这就是职场,这就是江湖充满尔虞我诈,真的人真是身不由己的,本想与世无争安心踏实做技术,但是某些人却看不得你的安宁。。。还是那句话,出来混的迟早要还的,望好自为之
右划
这公司是在拉勾上投的,CEO号称曾于字节跳动,任视频负责人,创建了头条视频APP。公司待遇15薪非常不错,坐落于望京Soho对面的望京融科写字楼
- 面试过程觉得自己挺失败的没有充分准备算法再加上由于一年半没有再面试过了,有点手生,好多应该答上来的问题都没有答好,面试官确实是大牛,没会的问题也稍微讲解了下,不过深度确实蛮深的
- 印象比较深的几个问题:Lru算法,Binder机制,EventBus实现原理和为什么不能跨进程,Handler如何在handleMessage方法拦截之前发出的message,手写二分法查找(没准备直接跪了),后来让我手写冒泡,我觉得前面已经没戏了(大致说了下双重循环然后赋值也没手写),跨进程几种方式,AIDL,handler机制,ThreadLocal实现原理(回答的很模糊,附上正确答案:每个Thread的对象都有一个ThreadLocalMap,当创建一个ThreadLocal的时候,就会将该ThreadLocal对象添加到该Map中,其中键就是ThreadLocal,值可以是任意类型。
在该类中,最重要的方法就是两个:set()和get()方法。当调用ThreadLocal的get()方法的时候,会先找到当前线程的ThreadLocalMap,然后再找到对应的值。set()方法也是一样。)系统是如何监听ANR的(他说是androidframework层有一个单独的进程),后来问到如何定位和排查我不小心说了blockCanary,他有追问了一下源码和原理我回答的也不是很好(应用发生卡顿,一定是在dispatchMessage中执行了耗时操作。我们通过给主线程的Looper设置一个Printer,打点统计dispatchMessage方法执行的时间,如果超出阀值,表示发生卡顿,则dump出各种信息,提供开发者分析性能瓶颈。)
最后知道今天一定挂了,不过还是很有收获的知道自己哪里不足...
PS:明天去五道口面试斗鱼,希望能好好把握
斗鱼
拉勾投的斗鱼,据说最近在疯狂裁人?只经历了两轮面试,一共面了两个多小时,没到HR,估计歇菜了
- 斗鱼有份笔试题,还是蛮简单的随便写写就ok,一面问的蛮详细的,问的大致是看简历写的东西问的,中规中矩,记忆比较深刻的是问了handlerThread原理,MVP模式(因为斗鱼目前的架构都是mvp),弹幕的实现原理和重叠问题(这个没怎么做过,回答的不是太好,而且之前也是直接用的B站开源的那个库),Kotlin协程(这个没用过,kt的掌握程度还只是入门阶段),Retrofit+Okhttp+Rxjava在华为的好多手机会OOM是由线程数溢出引起如何解决?堆内存,栈内存理解,栈如何转换成堆?内存泄漏是发生在堆内存还是栈内存?为什么? BlockCanary原理?(第二次被问了!!!看来真要看看源码了)如何实现打印指定阻塞线程的方法名?LinkedHashMap与HashMap区别。。。
String a=“A” 与 String a = new String(“A”); 区别,分别存储在哪个区域(这题有误导嫌疑,第一个应该是常量区,堆栈都不是,第二个是堆)MutiDex 第一次ANR以及解决方式(答案参考:https://www.jianshu.com/p/5a2e33a61ba2)
我觉得大部分的问题回答的还是不错的,一面问了下薪资然后开始二面 - 二面印象最深的是根据面向对象设计一个电梯系统,问题的关键点在于所有的属性都跟电梯有关,跟人无关,楼层数是固定的常量...我当时设计跑偏了,总联想到人然后去设计。。
结束以后没有HR面,估计歇菜了...再接再厉吧...
Zenjoy
这家公司是猎头推荐的,坐落于银河SohoA座,办公环境蛮不错的,产品方向是做海外项目的,不过前后历经将近三个小时的面试着实很令人崩溃,我喝了将近三瓶小瓶怡宝矿泉水才撑到了最后。。。
一面&二面
一面,二面问的太多了根本记不住,只记得几个印象深刻的问题,
- hashcode()和equals()的作用、区别、联系?
因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:
1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。) - Handler、Looper、MessageQueue、Thread关系?
一个线程可以有多个Handler实例,一个线程对应一个Looper,一个Looper也只对应一个MessageQueue,一个MessageQueue对应多个Message和Runnable。所以就形成了一对多的对应关系,一方:线程、Looper、MessageQueue;多方:Handler、Message。同时可以看出另一个一对一关系:一个Message实例对应一个Handler实例。 - Service 和 Activity如何交互, 如何在后台下载任务, 并在Activity显示进度?
- https握手过程,如何实现数据加密?客户端如何保证安全实现双重证书校验?请你设计一个登录功能,需要注意哪些安全问题?
- Hashmap实现原理和如何解决散列碰撞(必问),Hashmap底层为什么是线程不安全的?
- HandlerThread原理以及对比单个New Thread的好处,优点以及试用场景?需要注意的是HandlerThread 是单个线程的不太适合执行网络的IO操作,要注意。。
- EventBus实现原理
- SurfaceView, TextureView区别?
从性能和安全性角度出发,使用播放器优先选SurfaceView。
1.在android 7.0上系统surfaceview的性能比TextureView更有优势,支持对象的内容位置和包含的应用内容同步更新,平移、缩放不会产生黑边。 在7.0以下系统如果使用场景有动画效果,可以选择性使用TextureView
2.SurfaceView优点及缺点优点:可以在一个独立的线程中进行绘制,不会影响主线程,使用双缓冲机制,播放视频时画面更流畅
缺点:Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用
3.TextureView优点及缺点
优点:支持移动、旋转、缩放等动画,支持截图
缺点:必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程。 - handler postDelay这个延迟是怎么实现的?
- Appliction启动过程(App启动过程)?
- 如何测量应用启动时间?
1.可以通过代码打桩,计算启动时间
2.命令
adb shell am start -W [packageName]/[packageName.launchActivity]
三面
根据之前猎头的情报,三面是没有技术相关的问题的,但是我这个不一样,三面是总监面,首先先手写一个算法,不难,大致意思是:给你一个无序的数组,又给了一个目标值,如果这个数组其中有两个数相加等于这个目标值,请你输出对应两个数的下标?
思路也蛮简单的,直接Arrays.sort先排序 按升序来,然后双重循环就可以了。。。写完总监会问下单层for循环时间复杂度---
for(int i=1;i <=n;i++) //O(N);
for(int j=1;j <=i;j++) //O(N^2);
然后是
- 设计模式
- Restful接口规范 我俩争论了好半天
- 观察者模式的原理
大概能记得的就是这些,总监可能比较注重基础吧,自认为总体发挥一般可能一面和三面有一些瑕疵,主要二面有一些问题反问面试官也没有给我相应的解释比如那个handler postDelay怎么delay的。。。前前后后面了将近三个小时,最后HR进来让我回去等消息,我知道估计凉凉了。。。
莱熙科技
这家公司我依稀记得去年年初考虑新机会的时候,那时候还在职,偷偷去面过,真心觉得面试官总是问一些我意想不到的问题,原本是要拒了的,可是Boss直聘上HR小姐姐一再要求要我再来一次,我就安排了今天的第三面(第一面已经拿到offer但是工资与预期差距较大,而且没有太深的技术面再加上公司较小,与我预期的差距也很大就不写了)依稀记得大概一年零八个月前吧,那时候他们还没做海外项目,没想到现在的产品居然是我上家公司的同类竞品项目,他们做的叫LivU,Live Chat,在线视频聊天~于是我决定去试试水。。。
一面
面试官还是1年零八个月之前的小哥,问题问的果然没有辜负我对他的期望,因为产品做的都是一个路子还有用的框架也是Agora的,答起来轻车熟路,但是有好多让我耳目一新的问题
- 使用GreenDao如何实现创建表、关联表(一对一,一对多,多对多)?
- Java调用kotlin 如何不用companion object{}包裹?
我解答他之前一直纠结的:在Java中调用kotlin中静态的成员
如果一个类中所有的成员都是静态成员,将class改为object就不用每个方法都用companion object{}包裹了。但是小哥说据说是最新kotlin加个注解可以不需要这个包裹? - 断点续传实现
- 代理模式和装饰器模式区别?
- java io 装饰器模式。。当时问我用过的哪个包是装饰器模式,我没答上来!
- App启动速度优化?
- Android 5.0-8.0新特性
- Dalvik与ART区别?
- 进程保活?(伪命题)没有真正意义的进程保活,都是白明单才OK
- Retrofit CreateApi实现原理
二面
二面主要是总监面试,穿插了一些技术,不过总是暗示我来了需要加班啥的要我考虑清楚(我当然想你钱到位,啥都不是事)不过既然这么说了,因为我问了一些公司流程方面的事,他回答是产品快速迭代,本身需求不可能流程化,只能产品做出来去试水,然后再推翻,如此往复计划跟不上变化快,大致我想要的工作方式并不是这样,可能有点分歧,也可能由于本来之前本来三面三个小时心态崩溃,可能态度没有顺着他来,So二面失败,HR小姐姐招人的佣金也没了。。
PS:其实内心还是蛮想去的,不过由于之前可能这种工作流程不太适合我,我刚跳出坑,他可能看到了我的犹豫和顾虑吧,所以技术过了也把我Pass了。。不过佛系的我已经无所谓了。。
站酷(ZCOOL)
这家公司是拉勾投的,面试官貌似是帮别的部门招聘,应该是做一个在线教育的项目,听名字貌似叫“高高手”?遇到答的不好的题面试官都给予了细致的讲解,我觉得收获蛮大。
具体的问题大概都有:
- Retrofit 如何实现文件(或图片上传)接口是如何定义的
大意要回答multipart/form-data 文件上传表单中
它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。 - 自定义View的属性引用attr,styleable里定义的名称可否与系统已经存在的name重复?当然是不可以的,编译器会预先检查系统已经存在或者之前已经定义重复的
- 自定义View OnMeasure方法的三种Mode
UNSPECIFIED(未指定),父控件对子控件不加任何束缚,子元素可以得到任意想要的大小,这种MeasureSpec一般是由父控件自身的特性决定的。比如ScrollView,它的子View可以随意设置大小,无论多高,都能滚动显示,这个时候,size一般就没什么意义。
EXACTLY(完全),父控件为子View指定确切大小,希望子View完全按照自己给定尺寸来处理,跟上面的场景1跟2比较相似,这时的MeasureSpec一般是父控件根据自身的MeasureSpec跟子View的布局参数来确定的。一般这种情况下size>0,有个确定值。
AT_MOST(至多),父控件为子元素指定最大参考尺寸,希望子View的尺寸不要超过这个尺寸,跟上面场景3比较相似。这种模式也是父控件根据自身的MeasureSpec跟子View的布局参数来确定的,一般是子View的布局参数采用wrap_content的时候。 - WebView拦截Url和cookie相关?网页需要设置登录状态等情形
- Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
Android应用程序的主线程在进入消息循环过程前,会在内部创建一个Linux管道(Pipe),这个管道的作用是使得Android应用程序主线程在消息队列为空时可以进入空闲等待状态,并且使得当应用程序的消息队列有消息需要处理时唤醒应用程序的主线程。 - 解决Android多线程访问SQLite数据库死锁问题?database is locked
解决的办法就是保持sqlite连接单例,保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。也就是说是读写数据库时存在的同步问题,所以采用单例+同步锁的方法,并且在每次数据库操作后都关闭数据库 - Android多进程解决单个进程内存分配?
微信貌似也用了拆分多进程去降低单个进程的heapSize - Android如何实现大图加载?
- WeakReference使用场景?
- 在Service里实现下载如何刷新UI?
- Handler postDelay如何实现不阻塞UI线程?
1.postDelay()一个1秒钟的MyTask任务、消息进队,MessageQueue开始阻塞,Looper阻塞,mBlocked为true,在enqueueMessage的if中将needWake = mBlocked。
2.然后post一个新的任务、消息进队,判断现在A时间还没到、正在阻塞,把新的任务插入消息队列的头部(MyTask任务的前面),然后此时needWake为true调用nativeWake()方法唤醒线程。
3.MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;
4.Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续阻塞;
5.直到阻塞时间到或者下一次有Message进队;
心得
这次面试还算是比较全面的面试吧,无论是深度和广度问的都很深,面试之后收获了自己的不足,感觉自己表现还可以,可能由于这个岗位是刚开始招的,时间周期会很长不知道会不会给offer... 不过有收获就是好的~
整理下最近面试的几个常见问题
RxJava 变换操作符 map flatMap concatMap buffer?
- 常用的变换操作符
- map:【数据类型转换】将被观察者发送的事件转换为另一种类型的事件
- flatMap:【化解循环嵌套和接口嵌套】将被观察者发送的事件序列进行拆分 & 转换 后合并成一个新的事件序列,最后再进行发送
- concatMap:【有序】与 flatMap 的 区别在于,拆分 & 重新合并生成的事件序列 的顺序与被观察者旧序列生产的顺序一致
- flatMapIterable:相当于对 flatMap 的数据进行了二次扁平化
- buffer:定期从被观察者发送的事件中获取一定数量的事件并放到缓存区中,然后把这些数据集合打包发射
装饰器模式和代理模式区别
代理模式,注重对对象某一功能的流程把控和辅助。它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。
装饰模式,注重对对象功能的扩展,它不关心外界如何调用,只注重对对象功能的加强,装饰后还是对象本身。
所以:
对于代理类,如何调用对象的某一功能是思考重点,而不需要兼顾对象的所有功能;
对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其它功能,因为再怎么装饰,本质也是对象本身,要担负起对象应有的职责。
HashMap如何实现一个Key对应多个value?
其实就是Hashmap + ArrayList去实现的
例:
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);
Android中ClassLoader的种类&特点
- BootClassLoader(Java的BootStrap ClassLoader)
用于加载Android Framework层class文件。 - PathClassLoader(Java的App ClassLoader)
用于加载已经安装到系统中的apk中的class文件。 - DexClassLoader(Java的Custom ClassLoader)
用于加载指定目录中的class文件。 - BaseDexClassLoader
是PathClassLoader和DexClassLoader的父类。
因为遵循双亲委派模型,Android中的ClassLoader具有两个特点:
- 类加载共享
当一个class文件被任何一个ClassLoader加载过,就不会再被其他ClassLoader加载。 - 类加载隔离
不同ClassLoader加载的class文件肯定不是一个。举个栗子,一些系统层级的class文件在系统初始化的时候被加载,比如java.net.String,这个是在应用启动前就被系统加载好的。如果在一个应用里能简单地用一个自定义的String类把这个String类替换掉的话,将有严重的安全问题。
最后
即将入职某影视公司Android Leader岗,面试暂时告一段落,希望面试心得能帮到大家,祝大家好运~