这是我第五次去面试了,依旧被pass掉了。

这一次的笔试题目做的实在太差了,面试的话表现也不太行。一点点说…

面试官就是公司老板,应该是刚搬到厦门来,办公区没开灯、没开空调,还有人进进出出的搬东西。一起来的还有个面试前端的,面试的时候老板先是给我核对了一下笔试的答案,后面的题目我的回答基本都是错的,我觉得这时候面试已经没有希望了。老板先是问了问我们的学历,当知道我知识辅修了软件工程,主修是地理信息科学的时候,就开始疯狂的问我,专业主要干嘛,上了哪些课等等等等。我不得不佩服老板的知识面,从软件到GIS,从前端到物联网(旁边面试前端的哥们学的物联网)。

反正最后看了我的简历也没问太多,看到我再简历写了使用Redis+RabbitMQ来实现异步下单,平均响应时间从400+降到了100+,问我RabbitMQ可以直接实现异步了,为什么还用redis?用了redis响应回到400+。Well,Well,不知道当时是没听清他问的还是真的自己没反应过来,当时就呆哪了。现在我肯定会说:

首先我的下单过程有多次判断,比如现在是否到优惠券的抢购日期了,用户是否已经购买过了,因为要保证不超卖和一人一单,我将优惠券数据预热到了redis中,同时使用redission的分布式锁,因此redis是必须的。响应时间比较大时因为我使用JMeter进行了压测得的,压测的时候开启了1000个线程,在4秒内完成,属于高并发,因此对服务器压力比较大,才导致了响应时间比较长。在不是高并发的场景下,接口响应时间是20-30ms。在采用了异步处理的方式后由400降低了100,响应时间是有显著提升的。

还问了为什么会出现TheadLocal类(没错,不是问我怎么用而是为什么会被开发出来)😔,还有redis的原理,为什么redis查询比较快(我说数据存储在了内存中,他说不对)。这些都很原理了,我是觉得答不上来了。

其实,从看完笔试答案后,就是闲聊了,一会问问我们专业,一会让我讲讲我擅长的(什么都行)。

。。。

下面还是看一下很基础但是我错了的题吧!

  1. 装箱(Boxing)、缓存机制、引用比较(==)与内容比较(.equals())的区别
public static void main(String[] args) {  
    Integer x = 127;  
    Integer y = 127;  
    System.out.println("x == y: " + (x == y)); // true  
    System.out.println("x.equals(y): " + x.equals(y)); // true  
  
    Integer a = 128;  
    Integer b = 128;  
    System.out.println("a == b: " + (a == b)); // false  
    System.out.println("a.equals(b): " + a.equals(b)); // true  
  
    Integer c = new Integer(127);  
    Integer d = 127;  
    System.out.println("c == d: " + (c == d)); // false  
    System.out.println("c.equals(d): " + c.equals(d)); // true  
  
    Integer e = 100;  
    int f = 100;  
    System.out.println("e == f: " + (e == f)); // true  
    System.out.println("e.equals(f): " + e.equals(f)); // true  
}

请写出执行结果(答案已经写在代码里了)。

你应该知道的:

  • 缓存机制:Java 中的 Integer 类在 [-128, 127] 之间的数值范围内使用了缓存池(IntegerCache),使得这部分的 Integer 实例在自动装箱时返回的是同一个对象引用。
  • == 比较的是对象引用是否相同;.equals() 比较的是对象内容是否相等。
  • 当Integer与int进行比较时,会自动拆箱,比较值的大小

我的误区:当new Integer(127)时,虽然在 [-128, 127] 内但是它是一个新的对象

  1. Java 类的加载顺序、静态代码块、构造代码块与构造函数的执行顺序
public class ClassOrder {  
  
    public static void main(String[] args) {  
        Son son = new Son();  
    }  
  
}  
  
class Father {  
    public Father() {  
        System.out.println(1);  
    }  
    {  
        System.out.println(2);  
    }  
    static {  
        System.out.println(3);  
    }  
}  
  
class Son extends Father {  
    public Son() {  
        System.out.println(4);  
    }  
    {  
        System.out.println(5);  
    }  
    static {  
        System.out.println(6);  
    }  
}

请问输出顺序为?(答案:3 6 2 1 5 4)

你应该知道的:

  • 执行顺序:父类静态代码块(static {})-> 子类静态代码块(static {})-> 父类实例代码块 {} -> 父类构造函数 Father() -> 子类实例代码块 {} -> 子类构造函数 Son()

我的误区:认为实例代码块不会执行(我做项目的时候一次都没用过实例代码块,不知道是干嘛的,这次也算是查漏补缺了)

  1. Java 参数传递机制和对象引用
 public class StringVsBuilder {

    public static void main(String[] args) {
        String str = "Hello";
        StringBuilder sb = new StringBuilder("Hello");

        changeString(str);
        changeStringBuilder(sb);

        System.out.println("After changeString: " + str);
        System.out.println("After changeStringBuilder: " + sb);
    }

    private static void changeString(String s) {
        s = s + " World";
    }

    private static void changeStringBuilder(StringBuilder sb) {
        sb.append(" World");
    }
}

输出结果:

After changeString: Hello
After changeStringBuilder: Hello World

你需要知道的:

  • String是一个不可变对象,每次值变化时,引用地址也会发生变化
  • Java中参数的传递,如果是基本类型则是值传递,如果是引用类型则是引用传递

我的误区:我一直以为java是值传递,这个是真的怪我没好好学