拿到 阿里实习offer,经历了5次面试,其中4轮技术面,1轮HR面试。在这里分享一下自己的面试经验和学习总结。希望能够帮助更多的小伙伴。
我本科毕业于中南大学信管专业,真正开始学习Java是在大三下学期,研究生就读北航的移动云计算专业。刚开始也是小白,也是一步步成成起来的。需要提的一点是,你将来是需要靠这个吃饭的,所以请对找工作保持十二分的热情,而且越早准备越好。
一面
一面是在上午9点多接到支付宝的面试电话的,因为很期望能够尽快接到阿里的电话,所以非常兴奋。电话接通之后还是非常紧张的,毕竟是第一次这样的面试。
synchronized与Lock的区别,使用场景。看过synchronized的源码没
1.synchronized与Lock的区别
synchronized<—>Lock
- JVM<—>API
- 可重入
- 非公平锁<—>公平锁/非公平锁
- 不可判断,等待可中断<—>可判断,等待可中断
- 等待/通知机制<—>可实现选择性通知(锁可以绑定多个条件)
参考:京东18届一年半经验社招.md#synchronized和lock的区别必考
2.synchronized与Lock的使用场景
一般情况下两个都可以使用,这时候推荐使用synchronized,原因是虚拟机在未来的性能改进中会更偏向于原生的synchronized,但是在特殊场景下需要考虑使用Lock:
- 等待可中断;
- 公平锁
- 选择性通知
3.synchronized源码的了解
推荐阅读:
「阿里面试系列」分析Synchronized原理,让面试官仰望
JVM自动内存管理,Minor GC与Full GC的触发机制
1.JVM自动内存管理
①哪些内存需要回收?
不可能再被任何途径使用的对象需要被回收。
②怎么判断内存是够能够回收?
- 引用计数法:给对象维护一个计数器,每次被引用计数器的值+1,每次引用被释放,计数器的值-1,当计数器的值为0时,认为它不可能再被引用了。
- 可达性分析:从GCRoots向下搜索,走过的路径为引用链,当一个对象到GCRoots没有任何引用链相连则证明对象不可用。
由于引用计数法很难解决对象循环引用的场景,因此一般都使用可达性分析来判断一个对象是否存活。
③什么时候回收?
-
新生代的回收时机
新的对象需要在Eden区申请内存,但Eden区没有足够的连续的空间分配给对象会触发一次minor GC
-
老年代的回收时机
从新生代过来的对象需要在老年代申请空间,但老年代没有足够的连续的空间来分配,会触发一次major GC。
HotSpot VM 老年代给新生代做空间担保时,若老年代连续可用空间小于历次晋升到老年代对象的平均大小,触发一次major GC。
④如何回收?
-
回收算法
-
垃圾回收器
推荐阅读:
2.Minor GC与Full GC的触发机制
参考京东18届一年半经验社招.md#minor-gc和full-gc触发条件
了解过JVM调优没,基本思路是什么
第一步:JVM性能定义
- 吞吐量:重要指标之一,是指不考虑垃圾收集引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标。
- 延迟:其度量标准是缩短由于垃圾收集引起的停顿时间或者完全消除因垃圾收集所引起的停顿,避免应用运行时发生抖动。
- 内存占用:垃圾收集器流畅运行所需要的内存数量。
第二步:JVM性能调优原则
-
MinorGC回收原则: 每次minor GC 都要尽可能多的收集垃圾对象。以减少应用程序发生Full GC的频率。
-
GC内存最大化原则:处理吞吐量和延迟问题时候,垃圾处理器能使用的内存越大,垃圾收集的效果越好,应用程序也会越来越流畅。
-
GC调优3选2原则: 在性能属性里面,吞吐量、延迟、内存占用,我们只能选择其中两个进行调优,不可三者兼得。
第三步:进行调优
-
内存占用调优
- jvm内存分配&参数
- 计算活跃数据大小
-
延迟调优
- 优化新生代的大小
- 优化老年代的大小
-
吞吐量调优
- 选择合适的垃圾收集器
- 进行吞吐量测试,并内存占用调优和延迟调优进行微调。
推荐阅读:
如何设计存储海量数据的存储系统
- 实时计算+离线计算
- 索引
- 全文检索框架solr(前台)+ elasticsearch(后台)进行数据索引
- 存储形式
- 基础数据存储:MySQL
- 文本存储:mongodb
- 热点数据:Redis
- 数据容灾与高可用
推荐阅读:
缓存的实现原理,设计缓存要注意什么
①确认是否需要缓存
- 某个结果需要大量的CPU计算
- 数据库IO比较繁忙
②本地缓存选择
- ConcurrentHashMap:比较适合缓存比较固定不变的元素,且缓存的数量较小的
- LRUMap:如果不想引入第三方包,又想使用淘汰算法淘汰数据,可以使用这个。
- Ehcache:由于其jar包很大,较重量级。对于需要持久化和集群的一些功能的,可以选择Ehcache。
- Guava Cache:其本身是轻量级的而且功能较为丰富
- Caffeine:其在命中率,读写性能上都比Guava Cache好很多,并且其API和Guava cache基本一致,甚至会多一点。
③分布式缓存
- MemCache:其吞吐量较大,但是支持的数据结构较少,并且不支持持久化。
- Squirrel/Redis:支持丰富的数据结构,读写性能很高,但是数据全内存,必须要考虑资源成本,支持持久化。
- Cellar/Tair:支持丰富的数据结构,读写性能较高,部分类型比较慢,理论上容量可以无限扩充。
④多级缓存
- 进程内缓存
- 多级缓存
⑤缓存更新
- 先删除缓存,再更新数据库
- 先更新数据库,再删除缓存
⑥缓存问题
- 缓存穿透(不存在的数据直接访问数据库)
- 缓存击穿(热点数据过期)
- 缓存雪崩(同一时间过期多个数据)
⑦缓存监控
推荐阅读:
淘宝热门商品信息在JVM哪个内存区域
一般来说,热门商品信息存放在分布式缓存中,在JVM中一般存放在堆中。
操作系统的页式存储
把内存中的物理地址空间和程序中的逻辑地址空间各分成若干个大小相等的块,逻辑空间中的块称为页面,物理空间中的块称为物理块。
页式存储管理的优点是将作业的连续逻辑地址空间划分成页,可以分配到内存中不连续的块中,也就是分配到内存的不连续的主存区域中,并且能使作业正确的执行,这样进一步的提高了主存空间的利用率。缺点是当处理器处理一个作业时,必须访问两次主存,第一次是访问页表从而找到页号所对应的块号,然后换算出作业的绝对地址,第二次是处理器再按照换算出程序在主存中的绝地地址再进行运算操作。
推荐阅读
volatile关键字的如何保证内存可见性
被volatile
关键字修饰的变量,在每个写操作之后,都会加入一条store
内存屏障命令,此命令强制工作内存将此变量的最新值保存至主内存;在每个读操作之前,都会加入一条load
内存屏障命令,此命令强制工作内存从主内存中加载此变量的最新值至工作内存。
happens-before原则
①happens-before含义:前面一个操作的结果对后续操作是可见的。
-
如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
-
两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。
②happens-before原则
-
程序的顺序性规则:在一个线程中,按照程序顺序,前面的操作 Happens-Before 于后续的任意操作。
- 理解:同一个线程中前面的所有写操作对后面的操作可见
-
管程中锁的规则:这条规则是指对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。
- 理解:如果线程1写入了volatile变量v(临界资源),接着线程2读取了v,那么,线程1写入v及之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)
-
volatile变量规则:对一个volatile变量的写操作happen—before后面(时间上)对该变量的读操作。
- 理解:如果线程1写入了volatile变量v(临界资源),接着线程2读取了v,那么,线程1写入v及之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)
-
线程启动 start() 规则:它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
- 理解:假定线程A在执行过程中,通过执行ThreadB.start()来启动线程B,那么线程A对共享变量的修改在接下来线程B开始执行前对线程B可见。注意:线程B启动之后,线程A在对变量修改线程B未必可见。
-
线程终止 join() 规则:这条是关于线程等待的。它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。
- 理解:线程t1写入的所有变量,在任意其它线程t2调用t1.join(),或者t1.isAlive() 成功返回后,都对t2可见。
-
线程中断interrupt()规则:对线程interrupt()的调用 happen—before 发生于被中断线程的代码检测到中断时事件的发生。
- 理解:线程t1写入的所有变量,调用Thread.interrupt(),被打断的线程t2,可以看到t1的全部操作
-
对象终结finalize()规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
- 理解:对象调用finalize()方法时,对象初始化完成的任意操作,同步到全部主存同步到全部cache。
-
传递性规则:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。
推荐阅读:
Lucene全文搜索的原理
推荐阅读:
你觉得自己适合哪方面的开发,为什么
想去哪里实习,杭州?
反问面试官的问题
-
评价一下我的这次面试表现
-
应该在我的技术栈中增加什么
-
有机会下次面试吗
一面总结
一面大概面了50多分钟,从面试官口中得知他是一个老员工,比我大不了多少,总体上还是聊得蛮投机的。最后的三个问题是我问面试官的,在回答我是否还有机会下次面试的时候说:竞争很激烈,不过机会还是有的。
可以看出一面的问题不是很难,但是要得到面试官比较高的评价,还是需要一定的表达能力和对技术比较本质的认识的,如果在回答问题的时候能够做一些适当的扩展,自然会让面试官对你有不一样的评价。
我回答问题的遵循一定的步骤:先回答问题本质,在回答具体细节,最后做一些平时编程中的扩展。这样,会让面试官觉得你确实是在这个技术上面下过功夫的。
二面
等了将近6天(还以为被刷了呢)终于在第二周的周四接到阿里面试电话,那叫一个激动啊。赶紧找了一个安静的地方,准备好后开始正式面试。二面的面试官是一个部门主管,自然还是有点小紧张的。这次面试官上来就直接问,没有一面的面试官那么好说话。
自我介绍下自己,不超过3分钟(我的自我介绍仍然不超过1分钟)
你说你熟悉并发编程,那么你说说Java锁有哪些种类,以及区别(果然深度不一样)
-
乐观锁/悲观锁
- 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS(Compare and Swap 比较并交换)实现的。
- 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。比如Java里面的同步原语synchronized关键字的实现就是悲观锁。
-
独享锁/共享锁(具体实现互斥锁/读写锁)
- 独享锁:指该锁一次只能被一个线程所持有。例如ReentrantLock。
- 共享锁:指该锁可被多个线程所持有。ReadWriteLock其读锁是共享锁,其写锁是独享锁。
-
可重入锁:可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。ReetrantLock/Synchronized均为可重入锁。
-
公平锁/非公平锁
- 公平锁:多个线程按照申请锁的顺序来获取锁。ReetrantLock可以设置为公平锁(默认非公平锁)。
- 非公平锁:多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。Synchronized而言,也是一种非公平锁。
-
分段锁:是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。
-
偏向锁/轻量级锁/重量级锁
- 偏向锁:一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
- 轻量级锁:当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
- 重量级锁:当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让他申请的线程进入阻塞,性能降低。
-
自旋锁:在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
推荐阅读:
如何保证内存可见性
HTTP请求的过程与原理
①浏览器根据域名解析IP地址;
②浏览器与WEB服务器建立一个TCP连接
③浏览器给WEB服务器发送一个HTTP请求
④服务器端响应HTTP请求,浏览器得到HTML代码
⑤浏览器解析HTML代码,并请求HTML代码中的资源
⑥关闭TCP连接,浏览器对页面进行渲染呈现给用户
推荐阅读:
TCP连接的特点
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- 面向连接: 面向连接意味着使用tcp的应用程序在传输数据前必须先建立连接,就如打电话一样,要先进行拨号,等待对方响应才能开始说话。
- 可靠性(参见TCP连接如何保证安全可靠的)
- 字节流:两个应用程序通过TCP连接交换8 bit字节构成的字节流。
TCP连接如何保证安全可靠的?
- TCP协议采用发送应答机制,即发送端发送的每个TCP报文段都必须得到接收方的应答,才能认为这个TCP报文段传输成功。
- TCP协议采用超时重传机制,发送端在发送出一个TCP报文段之后启动定时器,如果在定时时间内未收到应答,它将重新发送该报文段。
- 由于TCP报文段最终是以IP数据报发送的,而IP数据报到达接收端可能乱序、重复、所以TCP协议还会将接收到的TCP报文段重排、整理、再交付给应用层。
- TCP提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
为什么TCP连接需要三次握手,两次不可以吗,为什么?
AOP的原理
AOP的思想是,不去动原来的代码,而是基于原来代码产生代理对象,通过代理的方法,去包装原来的方法,就完成了对以前方法的增强。换句话说,AOP的底层原理就是动态代理的实现。
动态代理与cglib实现的区别
参考:
pring AOP实现有哪几种实现,接口代理和类代理会有什么区别?
看过Spring源码没,说说Ioc容器的加载过程吧
Ioc容器的加载过程实际上问的是Spring的生命周期。
参考:java后端社招面试经历(三年工作经验).md#spring生命周期
了解过字节码的编译过程吗
主要过程:词法解析—>语法解析—>语义解析—>生成字节码
①词法解析:javac编译器执行字节码编译的第一步。主要任务就是将java源码中的关键字和标示符等内容转换为符合java语法规范的Token序列,然后按照指定的顺序规则进行匹配校验,以便为后续的语法解析步骤做准备。
②语法解析:将匹配后的Token序列整合为一颗结构化的抽象语法树。也就是说,词法解析后的Token序列其实还并不完善,因为这些Token所代表的只是一个对应的单个源码字符集合,还并没有按照指定的语法规则将其相关的一组或者一段Token整合起来。
③语义解析:为没有构造方法的类型添加缺省的无参构造方法/检查任何类型的变量在使用前是否都已经经历过初始化/检查变量类型是否与值匹配…
④生成字节码:是将符合Java语法规范的java代码转换为符合JVM规范的字节码文件。
推荐阅读:
反问面试官的问题
- 可以来杭州实习吗
- 评价一下我的面试表现
- 有机会下次面试吗
- 您觉得我的技术栈应该补充什么,有哪些方面还需要提高
二面总结
二面面试官问的问题都比较直接,答案也是知道就知道,不知道就不知道。这些问题一部分是基础,一部分是根据你的专业技能的来提问的。
面完后面试官对我的评价是:中规中矩,有机会下次面试。虽说是中规中矩,但听到面试官说有机会下次面试就感觉这次面试应该过了。
虽说这次面试过了,但是我在思考的是为什么面试官对我的表现是中规中矩。后面我知道我的回答虽然答到了点子上,但是扩展程度不够,对一些问题的理解缺乏足够的实践经验。面试官告诉我,有时间可以去研究字节码的编译过程,以及JVM调优方面的知识(特别强调这个很重要)。
针对自己的不足,面完后又投入疯狂的看书写代码的生活中。虽然在面试中有一些回答不出来很正常,但是如果能够做到出乎面试官的意料,也是面试官对你很重要的加分项。
三面(总监面)
三面与二面隔了5天,找了一个安静的地方开始电话面试。据说总监面会问项目多一点,所以在等待的这几天中给项目增加了几个比较肉的点。总监刚上来非常不客气,最尴尬的是总监那边老感觉有回声,因为不好意思提就忍了。
自我介绍,不超过3分钟(这次好像时间更久了,也就2分钟多点)
自由发挥,略
说一下你对哪个项目比较熟悉
自由发挥,略
为什么做这个项目
自由发挥,略
项目采用了什么架构,数据库如何设计的
自由发挥,略
数据库由哪些表,为什么有这些表
自由发挥,略
主要有哪些核心模块,模块之间如何通信的
自由发挥,略
session放在哪里?
存放于数据库。
如何保存会话状态,有哪些方式、区别如何
方式:session和cookie两种方式
区别:
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
推荐阅读:
分布式session如何管理,你有哪些方案?
1.直接将信息存储在cookie中
2.tomcat集群,tomcat之间进行session复制
3.Nginx进行ip-hash
4.Redis进行存储session
推荐阅读:
学过数据结构和算法吗(当然),你说说二分搜索的过程
public static int getIndex(int[] a,int x) {
int start = 0;
int end = a.length-1;
while (start<=end) {
int middle = (end+start)/2;
if(x==a[middle])
return middle;
else if (x<a[middle]) {
end = middle -1;
}else {
start = middle +1;
}
}
return -1;
}
说一下快排的过程,写一下伪代码
public class Sort_quick_sort {
public void quick(int[] src, int begin, int end) {
if (begin < end) {
//基准数
int key = src[begin];
int i = begin;
int j = end;
while (i < j){
//如果右边大于基准数,j--
while(i < j && src[j] > key){
j--;
}
//上面循环结束,说明右边不大于基准数了,换位置
if (i < j){
swap(src, i, j);
i++;
}
//如果左边的小于基准,i++
while (i < j && src[i] < key) {
i++;
}
//上面循环结束,说明左边不小于基准数了,换位置
if (i < j){
swap(src, i, j);
j--;
}
}
//当i== j的时候,基准数停留在了它应该在的位置,分而治之的递归下去
quick(src, begin, i - 1);
quick(src, i + 1, end);
}
}
public void swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String args[]) {
Sort_quick_sort obj = new Sort_quick_sort();
int[] num = {2, 7, 11, 15, 1, 0, 0,15};
obj.quick(num, 0, num.length - 1);
for (int n: num){
System.out.print(n+ "\n");
}
}
}
推荐阅读:
了解哪设计模式,举例说说在jdk源码哪些用到了你说的设计模式
三面总结:
本以为三面是交叉面,没想到是阿里的总监面试。由于具体的技术问题在前两轮面试中已经问过了,所以三面后不会有具体的技术问题,总结来看,对自己做过的项目一定要深入,包括使用使用到的技术原理、为什么要使用这些技术。
针对项目,面试官关注的无非以下几点:
- 项目中某个比较重要的点是如何实现的(需要深入技术的原理)
- 遇到的最大困难是什么(有哪些),你怎么解决的?
- 如果需要扩展某个功能,如何降低系统的耦合度
- 如果针对某个功能进行优化,你会怎么设计和优化
对于写在简历上面的项目,自己对照上面四个问题进行思考,才会在面试中游刃有余。因为任何在简历中作假的行为,面试官只要详细问你就露馅了。在听到面试官说有机会下次面试的时候,心中自然是非常高兴的。
四面(总监面)
果然,在第二天下午四点多接到了部门总监的电话,简单沟通后开始了面试。这次面试感觉是最放松的,没有什么高深的技术问题,感觉就像和朋友聊天的感觉,真的很感谢这位面试官。
下面是面试中的问到的问题:
- 来个自我介绍呗,不超过3分钟
- 介绍下你最熟悉的项目
- 项目使用了什么架构,亮点是什么
- 平时主要学习什么课程
- 你目前的研究方向是什么
- 家是哪的
- 喜欢看什么书
- 大概什么时候能来实习呢
四面总结:
虽然这面比较轻松,也没有什么具体的技术问题,但对项目仍然是面试官关注的,后面了解到总监面除了看你的基础,主要看你的潜力(就是有没有培养的价值),这个东西看起来挺虚的,但是从你平时的学习中仍然是可以看得出来的。所以,作为一名开发人员,平时对技术的研究也是很重要的。在听到面试官说让我好好等HR通知的时候可开心了,感觉饭都吃得更香了。
五面(HR面)
在隔了4天左右,终于接到了HR的电话,那叫一个激动啊。感觉离阿里offer已经不远了,于是振奋精神,聊得还不错。
下面是HR问我的问题:
- 自我介绍下吧
- 做了哪些项目
- 看你在问题中说你在杭州看到很多商贩使用付款二维码,你对支付宝怎么看
- 每天有那么多人使用支付宝,这些数据如果给你存储,你会怎么设计呢(不是说HR不问技术问题吗?不愧是阿里的HR)
- 为什么想来支付宝实习呢
- 你身边同学如何评价你、老师呢
- 如果与同事发生了意见的不一致,你会如何解决呢
关于HR面试:
其实早就听说HR面试的最终的录取结果具有一票否决权,在面完前面的技术面试之后,还是很担心的。所以咨询了师兄以及网上找了阿里HR面试的资料,大概得到以下结论:
- 诚信至上,所以在简历中不要存在任何虚假信息,企图通过虚假信息得到面试机会的后果得不偿失
- HR更关注你的表达能力、与同事相处的能力以及对工作的态度
- 对自己的是否一个明确的职业规划(前提是首先得对自己有一个清晰的定位)
- 关于待遇的问题(由于面的实习岗位,所以这个没有提,但是就我而言,能力才是最重要的,能力上来了待遇自然就水涨船高)
关于面试的心态:
在自己拿到阿里offer之前,一直都在想一个问题:我到底该如何做才能离阿里更近?一年的成长与思考让我认清了这点,虽然中间也遇到过很多坑,但却真正让我对自己有了一个清晰的定位,也有了比较明确的目标。正因为如此,我每天所学习的都给我莫大的动力,让我不断进步,并最终实现自己的目标。所以迷茫才是最可怕的,只有摆正心态,对找工作保持十二分的热情,勤奋努力,才能离目标更近一步。
但是有了目标和努力外,不一定就能实现目标,说到底还有一个运气的成分在里面,只能说你找到心仪的工作概率更大而已。遇到一个好的面试官绝对赚了。这四位阿里的面试官我感觉都挺好的,没有因为他们资历深就为难我,所以还是非常感谢这四位技术面试官的。
一点总结
由于本科是非科班出身,也仅仅是接触过Java而已,在大三的时候对自己的未来的发展道路很迷茫,不知道何去何从,感觉自己就是一个loser。那会考完研后有幸进入了金蝶实习,也就是那段时间让我认清了自己的短板,自己欠缺的是什么,那段时间也是我确立自己目标的过程。读研后疯狂看书、写代码、写博客、做项目,每天都在对自己进行总结和反思,正是这样一个不断的自我反思与努力的过程中,我得到了真正的成长与进步。也是这段经历让我能够面对阿里技术面试官的提问应答自如,从而顺利拿到阿里的offer。
最后,想送给自己两句话以鞭策自己
越努力,越幸运!以现在大多数人的努力程度之低,根本轮不到可以拼天赋。