学习自

https://www.cnblogs.com/ldq2016/p/9035649.html

 

1一面


 

阿里的面试官都很和蔼。一面面试官听声音感觉应该是入职两三年的感觉。上来自我介绍后直接开始问android相关问题。


 

大概问题如下:


 

·      android中的dp、px、dip相关概念

dp=dip

dp*density=px

density=dpi/160

dpi=斜长/屏幕尺寸

·      handler机制,四个组成部分及源码解析

一句话:一个消息队列,无限循环从中取消息

1.MessageQueue

2.Looper内部维护一个消息队列,Looper.prepare创建,Looper.loop开始取。(Looper存放在ThreadLocal中,一个线程只有一份。ThreadLocal.get的时候,从全局map中以当前线程为键,获取另一个map,然后以ThreadLocal自身为键,获取值)

3.Message

4.Handler,初始化的时候,会获取当前线程的Looper,所以Looper.prepare需要在Handler的实例化之前。

·      布局相关的控件作用及实现原理

merge+include用于消除一层布局,采用更外一层的布局,如果你想拆分xml,这个是一个不错的选择。原理,LayoutInflater的时候会进行判断。

ViewStub用于延迟加载,在实例化之前,不会占用任何资源。原理,调用的时候,删除自己,把子view添加到视图树上。ViewStub的LayoutParams生效,子View的根节点属性失效

·      android中的布局优化

1.嵌套伤在何处:linear、relative需要measure2次,如果重绘的话,会以指数级增长测绘次数

2.所以我们最好一层,最好自定义一些控件,比如textview drawable存于一个控件中

3.过度绘制,去除无效背景;自定义View要用好clipRect

4.merge、view stub

5.复用也要注意,这不属于优化,但是可以不怕需求变动

6.工具:gpu渲染、过度绘制、H…View的用于查看层级与查看绘制时间

7.绘制动画,最好用SurfaceView

·      relativelayout和LinearLayout在实现效果同等情况下选择使用哪个?为什么?

同层级,用后者,他更简单;

前者显然可以降低层级,这个时候用他;

·      view的工作原理及measure、layout、draw流程,要求了解源码

1.measure主要进行父控件的MeasureSpec或者Window+自身LayoutParams到自身MeasureSpec的一个转换(注意wrap_content情况);

2.layout,layout方法递归调用onLayout;

3.draw,源码没有了解太多,只知道他是一步步绘制什么部分的(注意setWillNotDraw或者dispatchDraw)

·      怎样自定义一个弹幕控件?

主要实现思路可以确认为位移动画(修改参数也可)。

我们在使用的时候可以设置N行,每行并行K个。

这样问题就转化成了设计一行了。(我们另外N-1行如法炮制就可以了。)

首先有一个发射时间差,还有一个位移速度,这是每个TextView的元数据。所以我们创建一个ViewHolder进行包裹TextView。(仿RecyclerView的非侵入式设计)还给每个ViewHolder定义一系列的状态,这样可以实现对TextView的复用。(所以我们这里也不局限于TextView了,可定制化的程度其实还是挺高的,像RecyclerView一样交给我们自己去实现,当然为了方便纯文本形式的弹幕,我们还需要再封装一次)。所以我们这里需要一个Adapter。如果有处于可用状态的ViewHolder就复用他,如果没有就创建。这一层就算封装好了。

然后再封装一层,只需要给我文本数据,我就可以去做,帮你省去了View的绑定文本的操作。

搞定!一天之内肯定能写出来。

·      如果控件内部卡顿你如何去解决并优化?

首先,检测到这个问题。用GPU Rendering。Systrace检测高耗时帧,看耗时方法

(我遇到过的)问题:绘制流程中存在耗时操作或创建对象。

解决:移除或者用对象池来cache

问题:A、B、C3块面积,C的path计算太复杂,在面积增大的时候,会爆掉(display list生成太慢)

解决:干脆直接绘制整个背景为C的颜色,然后C不绘制了,只绘制A、B。这样显然是过度重绘了,但是却很好地解决了我们的问题。(其实cache住path,也是可以的。)

·      listview的缓存机制

用的不多。但是知道他可以判断convertView==null来决定是复用还是创建;也可以创建ViewHolder来优化fvb

·      Invalidate、postInvalidate、requestLayout应用场景

invalidate draw这一族的需要重绘的并集区域。

postInvalidate

requestLayout会给当前View的parent打标记,这是递归的。最后对于被打标记的View,绘制流程要重新走一遍。

·      多线程,5个线程内部打印hello和world,hello在前,要求提供一种方法使得5个线程先全部打印出hello后再打印5个world。

单个线程的代码大概如下

System.out.print(“hello”);

System.out.print(“world”);

用while轮询效率肯定不高。

所以我们采用wait/notify+AtomicInteger

因为要群体唤醒,所以用wait/notify

因为要在子线程自增一个数,所以用AtomicInteger

private static AtomicInteger atomicInteger = new AtomicInteger(0);

static class
MyThread extends Thread {

   
private final Object object;

   
MyThread(Object object){
       
super();
        this
.object = object;
   
}

   
@Override
   
public void run() {
        Log.i(
TAG, "hello");
        int
currentValue = atomicInteger.incrementAndGet();

        synchronized
(object) {
           
if (currentValue !=5) {
               
try {
                   
object.wait();
               
} catch (InterruptedExceptione) {
                    e.printStackTrace()
;
               
}
            }
else
               
object.notifyAll();
           
Log.i(TAG, "world");
       
}
    }
}

当然也可以用Lock

·      实现一个自定义view,其中含有若干textview,textview文字可换行且自定义- - view的高度可自适应拓展

1.你大概会定义每行文字的个数。我只需要getText然后插入\n换行符即可。当然我还需要把这个text view的高度设置成wrap_content。

2.另一种思路,设置TextView控件的大小。我需要HOOK TextView的draw方法,拿到画一个字要多少宽高,然后进行计算。再给TextView设置宽高。这个思路不如第一个思路好。

3.view高度可自适应扩展。这个需要计算所有view的大小以及位置。我干脆继承某个布局好了。自适应扩展就实现了。要不然我还得定义measure、layout规则,我这不就自定义ViewGroup了?跑题了。

·      编程题:将元素均为1、2、3的数组排序。在手打了一种直接遍历三种数目并打印的方法后让手写实现,手写实现后让再说一种稳定的方法,说了一种通过三个下标遍历一遍实现的方法,读者可自行百度,在此不赘述。

如果2次遍历就太简单了。一次找到1、2、3各有几个,第二次按个数进行赋值。如果1次遍历呢?那么思路肯定就变成了:找到了立马就交换,只有这样才能保证O(1),但是怎么交换呢?就需要指针了。我们从最后开始找,自然是希望最后面的都是3。如果我们发现了第一个不是3的数,指针就指向他,停下来。再从前往后遍历,我们自然是希望最前面的都是1。如果我们发现了第一个不是1的数,如果是3,果断之前那个指针交换,如果不是3,那就是2,我们需要再开一个辅助指针,去寻找1,在找1的过程中如果发现了3,那么也是和第一个指针指向的值交换。如果发现了1就和我们指向2的指针进行交换。

思路还是挺简单的。

一面面完挺懵的,感受到阿里校招的火力,阿里的要求程度高于“知道、会用”那一层,你需要了解底层原理、机制才能过关。一面50min


 

一面面完,面试官说需要反馈面试过程后才能知道是否通过,后来了解到阿里的一面是“简历筛选”面,刷人不会太多。自我感觉良好,总体答出大概百分之八九十,面完便好好准备二面了。


 

2二面

 

二面很重要,二面很重要,二面很重要。二面对于你是否能通过面试,是否能最终从池子中被捞出来都很重要。一面面完的第二天下午收到来自杭州的电话,约了晚上九点的时间,且通知了视频面试和在线编程。


 

一阵慌张……看了那么多面经,没见过谁连续两次编程的……晚上九点,准时登录视频网址后,面试官已经在线。二面面试官稍显严肃,给人感觉非常严谨。上来简单自我介绍后,他说一面评价比较好,他会面试得细致一点,可能时间会稍长。当时心神一紧,做好了鏖战的准备。二面问的内容非常多,且覆盖范围很广,大概问题如下:


 

JVM方面


 

·      java内存模型,五个部分,程序计数器、栈、本地栈、堆、方法区。

pc 指令寄存器相关 存放下一条指令的地址 寄存器速度较快

栈 分native方法栈、Java方法栈

方法区 类的有关信息,比如Class的实例,静态引用,常量池等;

堆 存放对象

·      每个部分的概念、特点、作用。

·      类加载的过程,加载、验证、准备、解析、初始化。每个部分详细描述。

加载:

1.我们拿到这个类的全限定名,然后根据全限定名拿到二进制字节流

2.二进制字节流的静态数据结构转化成方法区的运行时数据结构(虚拟机所需要的格式:字节码

3.生成Class对象

验证:

我们比如从apk的类中加载Java类,而不是在本地编译器里写,那么他的正确性就无法得到保证了。

1.文件格式验证(比如是否以魔数开头等)。只有通过这个验证,才能转化成字节码

2.字节码表达的内容是否符合Java语法

3.字节码表达的语义是否合法

4.对这个类以外的东西验证,比如我真的能访问到那个private类吗?

准备:

static赋默认值,而非指定的值,初始化的时候才会这么做。这些内存是分配在方法区的。

解析:

符号引用替换为直接引用。怎么理解符号引用呢?比如我们A类想访问B类的某个方法,怎么定位它呢?所以B的字节码中对于那个方法就有一个符号引用。比如我们要访问一个类,怎么定位它的Class对象呢?这也需要解析。我们想访问他里面的一个字段,这也需要解析。

1.解析类/接口

2.解析字段

3.解析方法

4.解析接口方法

此外这个解析是有cache机制的。

初始化:

正式开始使用字节码。先对static变量进行赋值,再执行static代码块父类的静态先执行。而接口的话就不是了,父子接口,实现与被实现,静态执行都没有必然的联系。

·      加载阶段读入.class文件,class文件是二进制吗,为什么需要使用二进制的方式?

什么啊,class文件是16进制的,不信自己测试。只是在JVM的眼中,类的概念是二进制的。二进制字节流转化成字节码,这个操作,会被编译成若干机器指令,如果二进制,就能省去进制转换工作,可以快上很多。此外,机器指令都是二进制的,他们采用位运算,特别快。

·      验证过程是防止什么问题?验证过程是怎样的?加载和验证的执行顺序?符号引用的含义?

不安全。因为我们不一定从编译器编译的.class文件得来。

验证:

1.文件格式

2.Java语法

3.语义

4.这个类以外的,比如能访问吗

不一定的。加载的时候可能夹杂着验证。

符号引用:符号引用在字节码里用来定位一个类/接口、字段、方法。我们把他转化成直接引用。

·      准备过程的静态成员变量分配空间和设置初始值问题。

初始值是默认值,而不是我们定义的值。这些内存都是分配在方法区的!

·      解析过程符号引用替代为直接引用细节相关。

细节暂时没掌握,不过确实是理解了啥是符号引用了、以及几种符号引用的解析!以后有机会再回顾。

·      初始化过程jvm的显式初始化相关。

主要执行方法。对static变量赋值、执行static代码块

·      类卸载的过程及触发条件。

只有自定义的类加载器才能卸载。当你new出了类加载器的实例,并且用类加载器加载了类的Class对象和实际对象,把3者都置空,就可以卸载这个类了。

·      三种类加载器,如何自定义一个类加载器?

1.启动

2.扩展

3.应用程序

自定义类加载器:重写findClass,并从中调用defineClass(把字节码转化成类)

·      双亲委派机制。

就是上抛。比如Object类,不上抛,就可能出现多个Object类,这样就乱套了。

·      JVM内存分配策略,优先放于eden区、动态对象年龄判断、分配担保策略等。

优先分配Eden(8);

动态对象年龄判断:同年对象大小总和到达Survivor一半(1 1);

分配担保策略:看老年区的连续空间是否比将要升级的大。如果没有那么大,看看有没有一个可以冒风险的标记位,如果有再看看历次升级的平均大小是多少。尝试性地升级到老年代。如果担保失败,会full gc

·      JVM垃圾回收策略,怎样判对象、类需要被回收?

引用计数、可达。

·      四种垃圾回收算法标记-清除、复制、标记-整理、分代收集。

·      JVM中的垃圾回收器,新生代回收器、老年代回收器、stop-the-world概念及解决方法。

stop-the-world:垃圾回收器是同步的。

解决:后来逐渐有了异步回收器

新生代、老年代收集器没怎么关注过,以后有机会完整看一遍深入JVM吧。

·      四类引用及使用场景?


 

基本上JVM方面所有的大的概念全部问到,真的需要理解到位。JVM比较熟悉,全程巴拉巴拉不停地说,有惊无险。


 

集合类


 

初始引起话题的问题:hashmap了解吗?心中一喜,开启侃侃而谈(胡吹)模式。讲到了以下的一些点:


 

·      hashmap实现的数据结构,数组、桶等。

·      hashmap的哈希冲突解决方法:拉链法等。拉链法的优缺点。

链表太长的话,遍历也就是查找会影响性能。

·      hashmap的参数及影响性能的关键参数:加载因子和初始容量。

当前容量*加载因子。到达这个阈值就扩容。加载因子太大,链表就会增加,查找效率就变低了。加载因子太小,数组空间就浪费了。

初始容量

·      Resize操作的过程。

就是扩容一倍,然后具体的细节我也不太了解,&运算的时候会多放出来一位,所以hash方法扰乱后得到的东西,会被分成两批了,意思也就是在同一个数组位置上的东西,会分成两批。所以他是会重新走一遍,还是修改原有的数据结构,我不得而知。

·      hashmap容量为2次幂的原因。

计算出了HashCode,取余运算决定放在哪里,效率肯定不高。

所以我们用(容量-1)&hashcode的方法截取了hashcode的最后几位,高效地代替了取余运算。同时为了分布均匀,我们引入扰动函数,hashcode^ (hashcode>>>16)使得高低位都尽量保留彼此特征。
 

讲完一通之后,面试官挺满意,说了解地比较深挺好,抛出了下一个问题hashtable了解吗?又是心中一喜,一通介绍:


 

·      hashtable线程安全、synchronized加锁。

用的不多,在我印象里,就是锁住整张表。

·      hashtable和hashmap异同。

·      为什么hashtable被弃用?

效率。后来有了concurrenthashmap,1.8以前是以segment为分段而锁的。现在锁住每一个entry了。
 

果断将话题扯到concurrenthashmap,讲了concurrenthashmap相比于hashtable做的优化、segment的概念、concurrenthashmap高效的原因。中间面试官问的问题:


 

·      容器类中fastfail的概念。

其实很简单。在迭代器迭代的时候,他的count相关的字段,不和实际的add、remove后更新的count相等,这就导致了check方法中两个count不相等,然后就抛出异常了。

·      concurrenthashmap的插入操作是直接操作数组中的链表吗?

·      集合类相关over,由于都是自己主动在说,把握了主动权,相谈甚欢。


 

多线程


 

由于上面提出了concurrenthashmap的概念,顺理成章聊起了多线程。有了上一部分的经验全程我主动讲,面试官针对性问了一些问题,大概内容如下:


 

·      为什么要使用多线程?多线程需要注意的问题。上下文开销、死锁等。

相当于有100个人,你只让1个人干活,这不就浪费劳动力了。

注意的问题:线程的合理创建——线程池。并发的问题——数据可能不是我们预期想要的数据。CPU占用的问题——一个是死循环挤压时间片、一个是内核态用户态频繁切换、线程切换的开销。

上下文开销就是用来恢复现场的,因为是时间片轮转调度算法,在线程切换的时候,原来的线程保存线程,新的线程根据保存的信息恢复现场。

还有比如cpu是8线程的,如果我们创建8个线程,就不用轮转调度了。如果多了,就要轮转调度了。就有了上下文开销。

死锁就是大家都在循环请求资源。如果你想在Java中实现一个。先弄一个辅助线程sync obj1,然后线程1 sync obj2,然后判断sync obj1,显然是不行的;然后线程2反之。最后撤掉辅助线程,然后就死锁了。

·      java内存模型、导致线程不安全的原因。

线程会读取主内存变量到私有内存,然后修改后刷新回主内存。

读的以为是本地的,实际上只是拷贝

·      volatile关键字,缓存一致性、指令重排序概念。

缓存一致性就是上面讲的情况

就是为了更高速地运行,JVM会将一些指令重新排序。volatile就会在某个位置加入内存屏障,导致无法重排序。

·      synchronize关键字,java对象头、Markword概念、synchronize底层monitorenter和moniterexit指令。

对象头:mark world,存储元数据+指针。

monitorenter:锁计数+1

monitorexit:锁计数-1

·      lock语句和synchronize对比。

前者是对象级的锁。可以锁多条件。可以中断。是可以设置公平与非公平的。可重入,也就是获取了锁后再获取同一个对象的锁。

·      原子操作,CAS概念、相关参数。

就是先进行修改,再提交,不过先看看跟我们印象中的原值一样不一样。其实就是多条指令被打包成一条了。

·      乐观锁、悲观锁概念及使用场景。

乐观锁:cas。适合read频繁的。

悲观锁:读的时候,就不能更新了。适合write频繁的。

·      线程池概念、实现原理等。

分3块:核心线程(不被回收)、非核心线程(被回收,有生命时长限制)、队列。其原理,我认为1.对象池,合理管理Thread对象2.Thread运行完就会被关闭,这里会在里面续接任务,继续运行下去。

·      JVM锁的优化,偏向锁、轻量级锁概念及原理。

自旋——要请求一个对象,不会立刻挂起,而是先自旋一下,为了不频繁切换内核、用户态。无意义的锁,会被清除。分散的锁,会被合并。偏向锁认为只有一个线程来访问他。如果A线程已经访问过他,B线程来访问了,会检查A死了没,如果死了那就开始偏向B了,如果没死,就膨胀为轻量级锁了。轻量级认为竞争存在,一般会通过自旋来解决问题。如果自旋太多次或者自旋的时候,还有第三者插足,这个时候就膨胀为重量级锁了。
 

多线程方面回答得比较好,面试官反馈比较满意。


 

数据库


 

数据库方面笔者水平较菜,没有深入了解。面试官问了一个问题,


 

·      SQL语句中对表或者字段取别名有什么好处?

便于记忆?
 

并不知道怎么回答,面试官也没有再问数据库相关。之后面试官问了解操作系统,回答:没学过。面试官:好的 ,那不问了。心中感动得无法用言语形容。

?,数据库还能不学的吗?
 

通信协议


 

接下来是对通信协议的了解,大概问了下列问题:


 

·      TCP三次握手、四次挥手。

syn syn+ack ack

fin ack fin ack

四次因为服务端要发完报文,ack后延迟3秒关闭连接因为怕传送失败准备超时重传的。

·      http请求报文结构、响应报文,状态码。

请求行 协议版本、 url

body

header我按照自己印象深刻的来:

1.断点续传 客户端range:请求一个资源的部分、服务端contentLength获取要下载的资源的长度

2.强制缓存expires/cache-control 由客户端的服务处理中心决断

3.对比缓存 last-modified/if-modified-since(事件) etag/if-none-match(资源)由服务端决断

4.host 1.1考虑了虚拟主机

·      http2.0相比于http1.0的新特性,推送、多路复用、消息头压缩等。

header压缩的。多路复用的。推送的。很快。

spdy密文。TLS(HTTPS)相关。

扩展:HTTPS:client、server间有共享的密钥。发送的过程,需要公钥去加密这个密钥。我们让第三方机构去签名公钥,公钥+签名=数字证书。
 

通信协议问得不是太深,了解得比较好即可。面试官反馈比较好。最后就是问android了,面试官说感觉你android应该挺厉害的,当时真的是受宠若惊。


 

android


 

android是重头戏。由于之前已经了解挺多,android方面基础的没有多问,比较深入。大概有如下问题:


 

·      handler机制组成,handler机制每一部分的源码包括looper中的loop方法、threadlocal概念、dispatchmessage方法源码,runnable封装message等。

loop就是无限去取。然后如果为空,会阻塞到nativePollOnce方法上,释放资源。管道写会唤醒它。

ThreadLocal:等于创建线程副本。先以线程为键获取一个map,再以ThreadLocal自身为键获取存储的对象。

dispatchMessage:3重筛选:1.Handler.post(runnable)这里会把msg.callback字段置为runnable2.newHandler(runnable)3.sendMessage。这里会把msg.target字段置为handler。执行重写的handler的方法。

·      listview缓存机制、recycleview缓存机制。

(大概:2+一个屏幕可见的item+2)就是recycler view create的次数。

view holder定义了好几种状态。recycler负责管理这些状态,并且输送一些确定暂时用不到的item到recycler view pool(它用来多个recycler view共享item)中。

当需要显示的时候,会找那些不稳定状态的item,找不到再从pool中找,实在没办法就创建了。

·      bitmap高效加载,三级缓存等。

百度了第一个后我感觉:哪来的3级?网络tmd不就是cache到硬盘了?

百度了第二个后我感觉:软引用算一级,我觉得有可能

百度了第三个后我感觉:fresco用的匿名共享内存,这确实算一级。

高效加载:一个是缓存,还有一个是处理压缩。glide压缩了大小以及图片位色成565。当然还有inBitmap,复用了之前的内存区域。

我最近在考虑用libjpeg-turbo压缩成jpeg是否表现的会比565更优秀一点。

·      binder机制原理。

其实没搞透。

表层一点:方法调用依附data、reply两个参数。如果跨进程,就onTransact,这个方法运行在服务端的Binder线程池中。

底层一点:service manager中注册了所有的非匿名server。我们拿到的是server的代理对象。我们在方法调用的过程中,参数data,返回值reply,如果是跨进程的话,会进行一次拷贝。(所以我们需要使用binder,减少方法调用时的拷贝次数)

·      view的工作原理及measure、layout、draw流程。哪一个流程可以放在子线程中去执行?

这问题真tm尴尬。。。需要很好地掌握3大流程的源码。我觉得measure是可以的,只是计算宽高。 layout他是绘制在了不同的地方,而且我看他setFrame方法内部调用了invalidate。draw就不用说了。

·      draw方法中需要注意的问题?

ViewGroup默认不开启绘制。可以setWillNotDraw或者dispatchDraw。此外,不可有耗时操作与创建对象,所以对象要注意cache,还有path不可太过复杂,否则生成display list会耗时太久。

·      view的事件分发机制。

一句话,拦截他,就可以消费它。

父子拦截策略:在view group的dispatch方法一开始,就会根据,标记位(child控制的标记位)、intercept方法进行拦截。当然如果之前没有找到分发对象也直接拦截了。

还有许多细节:perform click被覆盖?onTouchListener更优先?TouchDelegate?view的onTouchEvent中return super为什么等价于return clickable?

·      android性能优化:布局优化、绘制优化、内存泄露优化、bitmap、内存泄露等。

内存:工具有profiler,leak,mat(大牛必备)。找出内存泄漏,说一下常见内存泄漏常见。还有就是内存抖动。还有许多细节。内存大户可以关注:数据,可以用protobuf;图片,更好的压缩与缓存。

·      内存泄露的概念?android中发生的场景?怎么解决?讲了handler、动画等。
可达,比如MainLooper->MessageQueue->Msg->Handler->Context这种情况

面试android方面的时候已经真正地淡定下来了,有条不紊地和面试官说了自己所有的理解。反馈也挺好。


 

算法


 

最后是一题在线编程,题目比较常规,是一题最大连续子序列,需要注意全是负数的处理,在此不赘述可自行百度。

这个简单了,直接dp

dp[i]代表包括最后一位的情况下,sum的最优解

if(a[i] > 0) dp[i]=dp[i-1]+a[i];

else{

if(dp[i-1]+a[i]>0) dp[i]=dp[i-1]+a[i];

else dp[i]=0;

}

if(dp[i] > sum) sum = dp[i];
 

写算法的时候发生了一个小插曲,由于面试官直接面的都是以java写的,而笔者比较熟悉C++写算法,面试官也不太熟悉c++编译(g++),面面相觑一会儿才成功编译输出结果。真心非常感谢二面面试官的细致和耐心,最好的一次面试体验。面试官说他的这一面他过了,还会有一到两轮技术面试,礼貌地感谢面试官之后结束了,至此二面结束。二面108min。关闭连接后长呼一口气和女友分享了喜报,经此一役,我知道我的阿里之路已走完半程。


 

为什么说二面很重要呢?因为二面是所以技术面试中最为细致、考察最为最为深入的一轮面试,后面的面试官会很大程度上参考这一面试的结果,并且据说这一面很影响评级。


 

3三面

 

二面过后的第二天下午收到三面电话,约了三点的面试,由于之前的面试都是晚上可以在教室完成(在此感谢女友,没有你的陪伴就没有一个好的环境完成面试),三点的时间点是上课时间也基本找不到空教室,所以在教师休息的小房间完成了三面面试。


 

三面面试官感觉是部门主管级别,上来自我介绍后开始问问题。问了一下简历上在学校做的一个android的项目,说一个难点,讲了推送(以前从没接触过,这段时间可以看一下),巴拉巴拉讲了一通极光推送,感觉面试官不是很感冒,问了极光推送的实现原理,笔者一紧张竟然忘了讲长连接……又问了华为实习的项目,难点,怎么优化……我扯了一通字母树(这个也可以学一下),感觉面试官还是不太感冒。这个时候已经有点慌张,然后……面试官开始问优缺点、之前签的公司、为什么想去杭州、你是怎么看待算法?还问了最优成就感的一件事情,你觉得为什么会获得一等奖?是不是因为对手太弱了(懵了……)?回答完直接问还有什么问题想问他…此时有点崩溃,感觉也答得不太好,问了还有哪些方面需要改善。然后结束了面试……三面29min


 

面完三面挺难受的,感觉反馈不是很好,没发挥好。难过了一会儿吃了个饭回图书馆继续看书。


 

4四面

 

当晚上我还在图书馆感怀阿里离我远去的时候,一个杭州的电话来了……和四面面试官约好了时间,做一个技术和综合素质方面的面试。急匆匆和女友去找到了一个空教室,9点电话如约而至。四面面试官感觉斯文儒雅,上来介绍这是一轮交叉面,最后一轮技术面试。照例自我介绍后,问了如下问题:


 

通信协议


 

TCP保证可靠传输的实现:停止等待协议、滑动窗口协议、流量控制、拥塞控制等。

停等:发一个分组就停,然后等待确认,再继续发。

滑动窗口:我把他理解成缓冲区,使得双方无需关注各自网络通畅情况。类似生产者消费者。

拥塞避免:先指数增长,到阈值后线性增长。收到3个重复ack代表丢失,直接减半;超时检测到ack也代表丢失,直接减到1。
 

项目


 

·      说一个你记忆比较深刻的功能:我讲了一个查看当前WiFi网络连接终端信息的功能的实现。

如果是我,热修复app compat兼容还有libjpeg-turbo,这两个是我记忆犹新的、还没解决的。还有一个探索人家sdk源码,然后实习了自己的项目需求,虽然比较水。

·      说一下你遇到的问题:讲了一个十几万级别的字符串的匹配通过字母树优化的问题。面试官听了后和我详细分析了一下,得到了一个更好的实现方法……当时一阵汗颜,班门弄斧了。

·      问了一下项目中使用到的三级缓存策略。


 

获奖


 

聊了聊获奖经历,中间是怎么学习的。面试官看了看前面的面试过程,说问了多线程了,那他就不问了……


 

数据库


 

数据库方面问了以下的问题:


 

·      索引的种类

普通索引

唯一索引

主键索引

聚集索引(非聚集索引)

·      B树、B+树、红黑树。

·      B+树和B树相比有什么优点,应用场景?

???

·      红黑树的一些特点?怎样保持平衡?


 

问着数据库,问着问着扯到数据结构那边去了……说完之后面试官是感觉你这些都有所准备啊,我说对,毕竟是面阿里,面试官笑了说我本来还准备问你一下八大排序的现在感觉你应该都会,我很自信(jian zha)地说对,我都会。至此,面试官说技术方面他没什么问题想问的了,他这是一轮交叉面,集团内部要求的,他是后台开发方面的,不懂android,问我还有什么想问的。笔者抛出了万金油问题,您觉得我还有哪些方面需要优化的。面试官哈哈一笑,说你们这些学生现在问的都是套路问题,他基本上回答的都是这个问题,然后说了一通感觉深度和广度都有,继续保持就好了。


 

四面48min。至此,笔者彻底放心。互道周末愉快后结束了面试。和女友分享喜报后,阿里之路的进度条已经走到80%了。至于为什么有交叉面,众说纷纭,不太清楚。

5五面(HR)

 

度过周末后照例去图书馆学习,在周一下午接到hr的电话。周末准备了一些常见的HR面试问题,结果一个都没问到,问到的问题大概如下:


 

·      关于之前一次笔试的编程题,为什么没有做出来?后来有思考过吗?

·      你签约的公司给的薪水是怎么样的?如果阿里给你offer,你是怎么考量这两个offer的?

·      为什么没有在之前实习的公司留下来?之前公司的主管是怎么评价你的?

·      你的优缺点?


 

最后日常问问题,万金油问题培养体系和晋升机制。面完告知一到两周会有结果,要从池子里综合考量捞出一批人给offer(心中一慌,毕竟走到最后的对手都不容小觑)。随后HR面试官加了微信,有问题可以在微信上交流。

 

6后续

 

面完HR安心地在备胎池里面躺着。等待的日子总是很难熬,一天一天地过去,各种打听消息,听说有的前几批的拿到了意向(offer),心里拔凉拔凉。在过去四天后,周五的下午问了HR面试官后得知offer已在审批,据说比较稳,就是走个流程。联想到之前面完腾讯hr在offer审批等了很久还是心难安,在熬过周末,周一和周二,offer已经审批了三天,焦虑程度与日俱增。周二晚上十点半的时候,在宿舍无聊刷新闻的时候,突然收到一条短信和一封邮件,打开后发现是录用意向书。


 

真的挺开心,长呼一口气,总算这条路走到了尽头。


 

以上是我的阿里春招之路的分享。


 

7总结

 

洋洋洒洒写到这边已经说了很多,也有一些经验和大家分享。从17年春招找实习到18年春招,找工作的日子真的很累,不过再累也要坚持。有幸参加过一些公司的面试,问的问题也都大同小异,主要是以下的一些方面:


 

·      java基础

·      集合类

·      多线程

·      JVM虚拟机

·      通信协议

·      数据库

·      操作系统

·      算法

·      你的技术方向

·      项目。


 

关于每个方面的复习后续会给出分享。


 

一些感慨


 

说一些个人感受吧,找工作其实很容易,一些公司单凭学历就可以让你进去上班,现在太缺程序员了,简单到你面试根本不聊技术谈谈人生、聊聊奖项就可以给你发offer,但是找一个好工作不易,数十上百个人抢一两个岗位很常见。


 

主要你怎么定义你对于“好”的理解,工资高?公司技术氛围好?行业地位高?工作安稳福利好?不加班?仁者见仁智者见智,没必要强行拿自己的价值观去评判别人的工作,最适合的才是最好的。所以在找工作的时候想清楚自己到底想要一个怎样的工作也是挺重要的,定义一个目标,努力去做,才是最重要的。


 

技巧小谈


 

关于面试的一些技巧,个人觉得最根本的还是拓展你的知识架构的宽度和广度,形成你的一套说辞架构。以多线程为例,问到你多线程?可以先从为什么要使用多线程?使用多线程有什么好处?使用多线程一定会比单线程好吗?多线程会导致什么问题?导致问题的java内存模型是怎样的?怎么解决这个问题?解决方法如volatile、synchronize关键字等它的底层实现是怎样的?你是怎么使用多线程的?使用线程池有什么好处……


如果你真正理解了并将它完善成一个体系,面试官让你说多线程,接下来10min,你可以一直讲完。面试的参照不是你和面试官相比如何,而是你和你的竞争者相比如何,如果上面这一套完善地讲完,面试官对你的评价可想而知。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Android(安卓)Window与WindowManager 理解与源码分析
  3. android:OKHttp的使用
  4. Android倒计时神器(CountDownTimer)
  5. Android复习笔记(6) -BrodCastReceiver (广播接收者
  6. android 关于Toast重复显示解决方法
  7. .Net程序员玩转Android开发---(20)Android绑定服务
  8. linux chrome运行android应用方法
  9. Android(安卓)ViewRootImpl 解析

随机推荐

  1. Android(安卓)System.exit(code) and and
  2. Mono For Android(安卓)开发入门系列——
  3. [置顶] 随了Android的大流,站入Google阵营
  4. Android 自定义动画 单个View平面位移以
  5. Android学习笔记:常用控件 RadioGroup和Ch
  6. 【eoe Android特刊】第二十五期 Android
  7. Android:(13)Intent消息传递
  8. android:layout_marginLeft指该控件距离
  9. Android图形显示系统——下层显示4:图层合
  10. MaterialDesgin之MaterialTextField