一般基础面试过之后,面试官会从项目经验,问一些关于项目开发的内容,所以你需要在面试之前针对你之前开发过得项目做详细的准备。比如面试官会让你介绍一下你的项目,你需要体现出这个项目的难点、你在项目中的贡献、项目的具体实 现等,有可能还会问到一些具体的细节,所以建议是实事求是去讲,但一定要对项目的模块非常清晰。除了技术面试以外,有时还有可能会考察一些软技能,比如面试官会考察你跨部门协作能力、沟通能力、时间管理、任务分配和职业规划等。
面试和考试一样,更多的还是要靠平时的积累和临场的发挥,因此不定时的总结是很重要的,因为很多内容不经常使用的话过一段时间之后就会忘掉,这样就会出现原本已经做过的东西,因为忘记了细节,结果在面试过程中没法很好地展现出来。就比如插件化、热修复这样的技术,其实原理相对来说比较简单,但是在开发的过程中会遇到很多很多的坑,如果没有一些关键点的文字记录,过一段时间之后可能就忘记了某段代码是用于什么⽬的。所以在做完一次需求之后尽量多总结项目中的难点,使用到的框架以及这个框架的原理,以及其中花费时间最多的地方。另外,Bug 最多的地方也要做总结一下原因,这样在面试前就不用把代码再翻一遍,了解一下的项目细节就可以做到游刃有余了。
对于复习,我们要对目前所从事的工作有一个全面的了解,我是通过画脑图来进入这个过程的,我会整体默想一遍大概的知识体系,画成类似下图。回想每个知识点可能考到的内容,记录下⾃⼰模糊的地⽅,然后去看⽹上同学们总结的⾯试题,再对每个题⽬都做⼀下回答。这是⼀个持续迭代的过程。当你预想的问题都可以回答上来的时候,就需要深⼊挖掘⼀下技术细节和深度了,⽐如我⼯作中开发了⼀个 PLT Hook ⼯具,这个⼯具可能是我参考开源项⽬并封装修改过来的,但对其中的细节并没有很了解,这个时候你就要对这个开源项⽬所涉及的内容做⼀次系统学了。
另一方面,面试是一个相互学习的过程,比如我比较擅长的内容,面试官就不一定擅长,所以面试时往自己熟悉的方向走是一个不错的选择,这样会在面试找那个提⾼⾯试官对⾃⼰的级别评价。
算法与数据机构
算法与数据机构基本是面试中的压轴环境,曾经,我到字节面试就是因为算法和数据结构不及格而面试失败。因此,如果要去大厂,算法是⼀定要复习的,在很多⾯试的过程中都会穿插算法题。⾯试的算法题⼀般不会很难,可以分为基础的数据结构,⽐如数组、链表、栈、队列、⼆叉树、堆的使⽤,这⼏种常⻅的数据结构的基础操作⼀定要很熟悉,⽐如链表逆置、删除、获取第 K 个元素、判断是否有环等, ⼆叉树翻转、深度遍历、层级遍历、求树深度、公共⽗节点等。另⼀种是常⻅的搜索、排序算法,这两类算法出现频率很⾼,⼀定要知道它们常⻅的⼏种实现⽅式,⽐如排序⽅式有冒泡、快排、插⼊、归并、堆排序等。注意这⾥⼀定不要简单地去记忆算法实现,因为⾯试的时候可能不会直接让你写出对应的算法,会出⼀些使⽤搜索或者排序算法来实现的题⽬,这类题⽬你可以去 LeetCode 上通过标签过滤出来。
另⼀部分的算法题则侧重于实战,主要集中在贪⼼、动态规划、分治算法、深搜⼴搜等,这⼀类的算法相对需要⼀些技巧性。但⾯试算法题通常不需要太多⾏代码就能完成,⼀般都是在⼏⼗⾏内就能完成的,所以你可以优先去找⼀些经典题⽬来做,⽐如爬楼梯、最⼤⼦序和、最大矩形问题等。但也会有⼀些相对复杂的题⽬是⼏种算法结合在⼀起的,⽐如⼆叉树的最⼤路径和就是深度搜索和动态规划⼀起使⽤的题⽬。除此之外,也可能会遇到通过其他问题引申出的⼀些算法题⽬,⽐如 HashMap 可能会引申出红⿊树的实现等。
接下来就是我整理的一些面试中应该具备的知识点:
第一部分:
Android
-
Android基础
-
FrameLayout(框架布局)
-
LinearLayout(线性布局)
-
AbsoluteLayout(绝对布局)
-
RelativeLayout(相对布局)
-
TableLayout(表格布局)
-
Activity生命周期
-
Activity缓存方法
-
Fragment生命周期
-
Service的两种启动方法
-
ContentProvider使用方法
-
三种动画的区别
-
Android的数据存储形式
-
Sqlite的基本操作
-
View树绘制流程
-
你用过什么框架,是否看过源码,是否知道底层原理。
-
图片缓存
-
IntentService的使用场景与特点
-
Context区别
-
Android内存泄漏总结
-
Handler内存泄漏分析及解决
-
Handler、Looper、Message、MessageQueue基础流程分析
-
Android性能优化
-
ListView详解
-
RecyclerView和ListView的异同
-
AsyncTask源码分析
-
插件化技术
-
自定义控件
-
事件分发机制
-
ANR问题
-
Art和Dalvik的区别
-
Android关于OOM的解决方案
-
Fragment
-
Activity&Fragment
-
SurfaceView
-
Android几种进程
-
APP启动过程
-
Activity启动流程以及界面展示过程
-
图片三级缓存
-
Bitmap的分析与使用
-
热修复的原理
-
AIDL
-
Binder机制
-
Zygote和System进程的启动过程
-
Android中的MVC,MVP和MVVM
-
MVP
-
Android开机过程
-
Retrofit源码分析
-
Glide源码分析
-
EventBus用法详解
-
EventBus源码分析
-
Android ORM 框架之 greenDAO 使用心得
-
Data Binding(数据绑定)用户指南
-
RxJava
-
设计一套图片异步加载缓存方案
-
Android UI适配
-
Gradle
-
查漏补缺
-
Git操作
设计模式
-
面向对象六大原则
-
单例模式
-
Builder模式
-
原型模式
-
简单工厂
-
工厂方法模式
-
抽象工厂模式
-
策略模式
-
状态模式
-
责任链模式
-
解释器模式
-
命令模式
-
观察者模式
-
备忘录模式
-
迭代器模式
-
模板方法模式
-
访问者模式
-
中介者模式
-
代理模式
-
组合模式
-
适配器模式
-
装饰模式
-
享元模式
-
外观模式
-
桥接模式
第二部分
Java基础
-
八种基本数据类型的大小,以及他们的封装类
-
Switch能否用string做参数?
-
equals与==的区别
-
Object有哪些公用方法?
-
Java的四种引用,强弱软虚,用到的场景
-
Hashcode的作用
-
String、StringBuffer与StringBuilder的区别
-
try catch finally,try里有return,finally还执行么?
-
Excption与Error区别
-
Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况
-
OOM
-
Java面向对象的三个特征与含义
-
Override和Overload的含义与区别
-
Interface与abstract类的区别
-
Static class 与non static class的区别
-
java多态的实现原理
-
foreach与正常for循环效率对比
-
反射机制
-
String类内部实现,能否改变String对象内容
-
try catch 块,try里有return,finally也有return,如何执行
-
泛型的优缺点
-
泛型常用特点,List能否转为List
-
解析XML的几种方式的原理与特点:DOM、SAX、PULL
-
ArrayList、LinkedList、Vector的底层实现和区别
-
HashMap和HashTable的底层实现和区别,两者和ConcurrentHashMap的区别
-
HashMap的hashcode的作用?什么时候需要重写?如何解决哈希冲突?查找的时候流程是如何?
-
Arraylist和HashMap如何扩容?负载因子有什么作用?如何保证读写进程安全?
-
TreeMap、HashMap、LinkedHashMap的底层实现区别
-
Collection包结构,与Collections的区别
-
Set、List之间的区别是什么?
-
Map、Set、List、Queue、Stack的特点与用法。
-
Java中的内存泄漏
-
String源码分析
-
Java集合框架
-
ArrayList源码剖析
-
LinkedList源码剖析
-
Vector源码剖析
-
HashMap源码剖析
-
HashTable源码剖析
-
LinkedHashMap源码剖析
JVM
-
JVM基础知识
-
JVM类加载机制
-
Java内存区域与内存溢出
-
垃圾回收算法
Java并发
-
Java并发基础知识
-
生产者和消费者问题
-
Thread和Runnable实现多线程的区别
-
线程中断
-
守护线程与阻塞线程
-
synchronized
-
多线程环境中安全使用集合API
-
实现内存可见的两种方法比较:加锁和volatile变量
-
死锁
-
可重入内置锁
-
使用wait/notify/notifyAll实现线程间通信
-
NIO
第三部分
数据结构
-
数组
-
链表
-
栈和队列
-
字符串
-
树
-
图
算法
-
排序
-
选择排序
-
冒泡排序
-
快速排序
-
归并排序
-
查找
-
顺序查找
-
折半查找
-
《剑指Offer》
-
《程序员面试金典》
-
《LeetCode》
第四部分
网络
-
TCP/UDP
-
HTTP
-
Socket