大家好,我是程序员小灰。小灰有一位读者朋友鹤涵,是一个8年Java经验的资深程序员,并且当过多年面试官,面试过的人数超过百人。
今天,小灰特意把他邀请过来,给大家分享一下面试的一些方法,流程、实际案例,以及自己的思考。这篇分享非常良心,强烈建议大家收藏一下。
一、面试方法
一)考察点
面试主要考察:技能、能力、价值观、匹配度
1、技能
一个程序员技能过关才能完成日常开发任务,所以基础知识也是面试的必考内容。
一个Java程序员需要掌握的技能还真不少。Java基础,开源框架,中间件,代码设计,项目实战通通得会。
针对上面的每个Java技术栈的知识点,都有多年的面试题积累了(俗称「八股文」),面试前一定要过一遍,要求广度。
实际工作项目中使用到的技术一定要重点掌握,要求深度。
下面是我整理的知识点详细的脑图:
2、能力
工作年限和职级越高,对能力的要求越大,对技能的要求反而没那么大。
学习能力:
世界变化太快,尤其是在IT行业。面对新的知识和技能时,具备快速学习的能力至关重要,能够迅速掌握并应用新的知识。
沟通能力:
能够清晰、准确地表达自己的想法和观点,并理解他人的意见和观点,以进行有效的沟通和交流。
作为程序员,不仅仅需要会写代码,还需要具备良好的沟通能力。即使不直接面对客户,与产品经理、测试同事、领导和下属之间也需要进行频繁的沟通。
3、价值观
当设定了自己的目标和追求时,面对困难和挑战,是选择坚持不轻易放弃,持之以恒地努力追求目标,还是选择轻易放弃?
这是否与公司的价值观一致?是否具备以公司事务为己任的owner意识?听起来确实有一些「PUA」优点,但这样做确实能在职场获得较好的回报。
4、匹配度
而面试官的目的是找到适合职位要求的候选人。
需要注意的是,这里所说的是"适合"的人选,而不是"最好"的人选。这不仅考虑到用人成本,还考虑到员工的职业发展和工作质量。许多面试官不会选择经验和技能过剩的应聘者,而是选择经验和技能匹配,甚至稍微差一些,但是具备潜力和动机的应聘者。这样的人选会更加珍惜这个机会,对工作充满兴趣,更有动力去接受挑战,主动学习并将工作做好。
二)表达技巧
1、金字塔法则
金字塔原理是美国人巴巴拉·明托提出的一种关于思考逻辑的方法论。它很简单,核心思想是任何事情都可以归纳出一个中心思想,中心思想可由三至七个论点支持,每个论点可以由三至七个论据支撑。这样延伸下去,形状像一个金字塔,所以才叫金字塔原理。
我们在讲解自己的工作经历的时候就比较适合金字塔法则。
先把我们最重要的优势先提出来,然后按照时间顺序从近到远讲解自己的工作经历。用实际做的事来印证我们的优势。
2、STAR法则
STAR法则是一种在面试中有效回答问题的方法。它包括以下几个步骤:
- Situation(情境):描述你所面临的具体情境或挑战。
- Task(任务):解释你在该情境下的任务或目标。
- Action(行动):详细说明你采取的具体行动步骤。
- Result(结果):阐述你的行动带来的具体结果和成就。
使用STAR法则可以帮助你在面试中清晰、有条理地回答问题,展示自己的能力和经验。
我们讲解做过的项目的时候非常适合使用STAR法则。
先介绍我们项目的业务背景技术背景,再说明当前要做一个什么事,然后说明具体的技术方案以及如何落地,最后说明我们这个项目取得了什么结果。
这样面试官就比较容易理解,就会认为面试者逻辑性很强。
3、学会倾听
面试官问一个问题,即使你刚好很熟悉也一定不要「抢答」。一个是可能根本没有理解面试官的问题,二打断别人还是不太尊重的。面试官也是个最普通的人,是人就会被情绪操纵,留下不好印象很可能会影响这次面试的通过率。
面试官就是你的未来同事,你可以把面试官当成你的工作搭档去沟通,方便去做双向筛选。
二、面试流程
一般技术人员的面试为2-3轮技术面,一轮hr面试。
- 一面:
- 一般是跟你同级别技术能力比较强的同学。主要会考察技能是否过关,做一个初步筛选。
- 二面
- 一般是你的直系领导,你的升职加薪的直接负责人。主要会考察技能和能力,以及是否适合当前的岗位。
- 三面
- 一般是你的大领导,跟你直接的工作合作机会不会很多,绝大部分都不负责一线开发工作了。所以技术考察会少一些,会更看重能力,价值观等软性能力
- hr面
- 恭喜你,终于到了hr面。基本到了hr面只要不作死就安全了。hr主要是聊得内容不外乎职业发展,个人情况,离职原因,期望薪资这些。会根据你前面的面评和对标公司是否有offer来给你定薪资。
三、面试实战
一般Java面试会围绕项目,知识点,算法三个点进行展开。
其中最重要的是项目,因为公司招人一定是来干活,来解决公司的业务问题的,所以对以往项目的考察就比较重要了。
一)自我介绍
第一个阶段就是自我介绍,这个时间就是给面试官制造一个第一印象。用上面的金字塔原则把自己最突出的优势讲出来,引导面试官问你最擅长的部分,否则问到你不擅长的答不上来就会减分。
比如你学熟悉的是JVM调优,那你就是重点提一下,在后续的项目中也可以反复提起这个点。
案例如下
-
面试官:
-
你先做个自我介绍吧?
-
面试者:
-
我毕业于西虹市大学,有5年的工作经验。
-
平常使用Java技术栈偏多,熟悉Spring,Mysql,微服务等技术栈(擅长的)。
-
最近在西虹市保险公司做Java工作,目前在职状态,在公司里做了架构设计,性能优化,项目管理等工作(做出成绩的)。
-
再上一家公司同理。
二)项目
项目是信息量最大的部分,能真是反应你的工作状态。写出来的代码是能用就行,还是对边界控制,代码性能,架构设计有自己的思考。
案例如下
- 面试官:
- 挑一个你最具技术挑战或者成长最大的项目讲一下?
- 面试者:
- 我们所在的部门是商业化部门,承担了公司的主要营收任务,日收入大约200万。我们小组开发的投放平台旨在为广告主维护广告信息,我在里面承担组长的角色。
- 该项目主要是使用了Spring,Mysql,Redis等等技术。
- 由于广告量不断增长产生了严重的性能问题,所以做性能优化。
- 我使用了Java内存分析的方式进行分析优化,最终实现了内存下降了80%。
三)知识点
根据上面项目中使用的技术,进行知识点追问,有的面试官可能会刨根问底到操作系统层面。
案例如下
-
面试官:
-
我看你们用Mysql,在使用Mysql的过程中遇到什么问题了么?
-
面试者:
-
我们遇到了误用Mysql中的limit分页,导致Mysql负载飙高的问题。
-
MySQL的LIMIT子句常用于分页,但在处理大量数据时,如果不加注意,它可能会导致效率问题,特别是当你使用了偏移量。例如:
-
SELECT * FROM table_name ORDER BY id LIMIT 100000, 10;
-
这个查询会找到前100,010个记录,但只返回最后10个。这意味着前100,000个结果实际上是无用的,但仍然会被MySQL检索出来,这会造成不必要的I/O和CPU负载。
-
我们对 SQL 进行了优化,去掉了大 limit,改成先通过 id 过滤,再对 id 排序,最后使用 limit 的方式解决了这个问题。
-
SELECT * FROM table_name where id>100000 ORDER BY id limit 10
-
面试官:
-
嗯,那上面的id在Mysql一般是用什么数据结构存呢?
-
面试者:
-
MySQL中最常用的存储引擎是InnoDB,id主要使用B+树作为其索引结构。B+树是B树的一种变体,特别适合于磁盘或其他直接访问辅助存储器。
-
以下是B+树的特点和结构:
-
B+树在数据库中的使用是为了充分利用块访问的优点,并减少数据查找时的磁盘I/O次数,从而提高查询的性能。
四)算法
算法常见的就是考leetcode原题,或者基于场景的代码编写。
我一般不考leetcode原题,因为意义不大,背过了就会没背过就会卡壳,即使是高手也没有AI写得快。
应该重点考核工作中实际场景如何解决问题。
我一般会考两个线程交替打印奇数偶数。这道题的的难度不是太大,既能考察面试者的代码能力,也可以考察对多线程的熟悉程度,而且可以深入考察多线程的知识点。
-
面试官:
-
写一个代码两个线程交替打印奇数偶数
-
面试者:
-
可以使用wait()和notify()方法来实现线程间的协作。
-
我们使用了一个共享的锁对象LOCK。奇数线程和偶数线程会轮流获取这个锁,然后检查当前数字是否符合它们的输出条件。如果符合,就输出数字,增加数字并唤醒其他线程;如果不符合,就让当前线程等待。
-
public class AlternatePrint {
private static final Object LOCK = new Object(); private static int number = 1; private static final int MAX = 100; public static void main(String[] args) { Thread oddThread = new Thread(() -> { while (number <= MAX) { synchronized (LOCK) { if (number % 2 == 1) { System.out.println(Thread.currentThread().getName() + " : " + number); number++; LOCK.notify(); } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }, "OddThread"); Thread evenThread = new Thread(() -> { while (number <= MAX) { synchronized (LOCK) { if (number % 2 == 0) { System.out.println(Thread.currentThread().getName() + " : " + number); number++; LOCK.notify(); } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }, "EvenThread"); oddThread.start(); evenThread.start(); }}
-
面试官:
-
还有别的实现方式么?
-
面试者:
-
使用volatile关键字可以确保一个变量的读写操作对所有线程都是可见的,也即某一个线程修改了一个volatile变量后,其他线程可以立刻看到修改后的值。
-
为了使用volatile来控制两个线程交替输出,我们可以使用一个volatile标志来指示哪一个线程应该进行输出。
-
我们使用了isOdd这个volatile变量来标记当前应该由哪个线程输出。当isOdd为true时,奇数线程输出数字并递增,然后设置isOdd为false。当isOdd为false时,偶数线程输出数字并递增,然后设置isOdd为true。
-
使用volatile的这种方法可能导致CPU的忙等待,因为线程会在一个循环中不断地检查isOdd的值而没有进入休眠状态,这可能会增加CPU的使用率。
-
public class AlternatePrintVolatile {
private static volatile int number = 1; private static final int MAX = 100; private static volatile boolean isOdd = true; // true means Odd thread should print, false means Even thread should print public static void main(String[] args) { Thread oddThread = new Thread(() -> { while (number <= MAX) { if (isOdd) { System.out.println(Thread.currentThread().getName() + " : " + number); number++; isOdd = false; } } }, "OddThread"); Thread evenThread = new Thread(() -> { while (number <= MAX) { if (!isOdd) { System.out.println(Thread.currentThread().getName() + " : " + number); number++; isOdd = true; } } }, "EvenThread"); oddThread.start(); evenThread.start(); }}
-
面试官:
-
volatile的实现原理是啥?
-
面试者:
-
blabla..(又过去十分钟)
-
面试官:
-
整挺好!
四、最后
是金子总会发光,希望大家都能找到心仪的工作。