8年经验的老程序员,告诉你如何看透面试、通过面试

2023-11-06 18:40:25 浏览数 (1)

大家好,我是程序员小灰。小灰的公众号里有一位读者朋友鹤涵,是一个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子句常用于分页,但在处理大量数据时,如果不加注意,它可能会导致效率问题,特别是当你使用了偏移量。例如:

代码语言:javascript复制
SELECT * FROM table_name ORDER BY id LIMIT 100000, 10;

这个查询会找到前100,010个记录,但只返回最后10个。这意味着前100,000个结果实际上是无用的,但仍然会被MySQL检索出来,这会造成不必要的I/O和CPU负载。

我们对 SQL 进行了优化,去掉了大 limit,改成先通过 id 过滤,再对 id 排序,最后使用 limit 的方式解决了这个问题。

代码语言:javascript复制
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。奇数线程和偶数线程会轮流获取这个锁,然后检查当前数字是否符合它们的输出条件。如果符合,就输出数字,增加数字并唤醒其他线程;如果不符合,就让当前线程等待。

代码语言:javascript复制
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的使用率。

代码语言:javascript复制
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..(又过去十分钟)

面试官:

整挺好!

四、最后

是金子总会发光,希望大家都能找到心仪的工作。

更多精彩内容,欢迎关注公众号程序员贺涵

0 人点赞