转载

随便分享点不那么常规的面试题(一)

本题主要考察对linux的使用深度,属于加分项,没有用过awk至少要让面试官知道你用过grep,如果都没有用过的话,面试官会怀疑你是否有linux的使用经验

awk是一个文本分析工具,将文件逐行读入,然后默认按空格进行切片,对切开的部分进行单独分析

格式是 awk [options] '{command}' filename ,如 awk '{print $1}' out.txt ,其中 $1 代表第1列,awk会默认按照分隔符来切分每一行

分隔符也可以通过在awk后使用-F来指定,如 awk -F ':' '{ print $1 }' out.txt

3. 数据库水平分表之后怎么查询

本题主要考察你是否有考虑过分表之后的事情,而不是仅仅背了几道面试题,说出聚合操作后这道题基本就通过了

如果查询单条记录,可以根据查询条件和分表规则找到对应的表,然后进行查询并返回结果

如果查询多条记录,则分开查询,将所有查询结果做聚合,将聚合后的结果返回

4. mysql中 select *** from *** limit offset, rows 会有什么问题,怎么解决

本题主要考察数据库查询优化的知识,至少要能给出两种解决方案,并说出其各自的优缺点

存在问题:当offset很大时,查询效率会降低,因为mysql并不能直接定位到offset处进行查询,而是查询前 offset+rows 行,然后只取后rows条数据,将前面的数据舍弃,所以效率会很低

解决方案:

  1. limit offset, rows 删去,使用 where 主键 > offset limit rows 代替,但是使用前提是没有其他where条件对数据进行过滤
  2. 在子查询中查出索引,外层查询根据索引来定位数据,前提也是不能有其他where条件对数据进行过滤
  3. 如果偏移量超过记录数的一半,则反序查询,可以保证偏移量不会超过记录数的一半
  4. 限制limit的偏移量,不允许超过某个值
  5. 用额外的表记录数据和页数的关系,但是只适用于每页条数固定的情况

5. Java中final的实现原理是什么

本题主要考察一些语言层面上的知识,如果知道泛型是语法糖的话,这个问题也能很容易回答出来

Java中final和private、泛型一样,都是一种编程约束,编译器会检查final修饰的变量是否被重新赋值等,在编译后与普通变量没有区别

8. Java是编译型语言还是解释型语言,JVM是编译器吗,什么是JIT?

本题主要考察对Java语言的熟悉程度,能全部说正确当然最好,至少也得要能说出JVM是解释器,Java是解释型语言

Java既是解释型语言也是编译型语言。Java代码需要经过javac编译器 编译 成class文件,交给JVM进行 解释执行 ,为了加快执行效率,同时Java引入JIT编译技术(Just-in-Time Compile,即时编译技术),将部分热点代码 编译 成机器码优化执行

7. 逃逸分析了解吗

本题主要考察对Java优化技术的了解程度,属于加分项,回答好的话能给面试官留下深刻印象

Java引入JIT技术后,会将热点代码编译成本地机器相关的机器码,编译时会进行相应的优化,逃逸分析就是JIT优化的基础

一个对象在方法中被定义后,如果被外部方法所引用,比如通过参数传递给其他方法,就叫做(方法)逃逸。同样地,如果一个对象能被其他线程访问到,也叫做逃逸。逃逸分析就是来分析对象是否发生了逃逸,通过逃逸分析,Java编译器可以分析出一个对象的使用范围

当JIT使用逃逸分析时,可以执行相应的优化策略:

  • 同步省略/锁消除 :如果同步块只能被一个线程所访问,则加锁是没有必要的,在优化时,同步块上的锁会被省略
  • 对象分离/标量替换 :如果一个对象不会发生逃逸,则将对象属性的引用替换为标量,从而避免创建对象
  • 栈上分配 :将不会发生逃逸的对象直接在栈上分配内存,而不是堆中,这样可以省略垃圾回收的操作(实际上还是使用标量替换来完成的,没有真正实现栈上分配)

逃逸分析这项技术至今仍不成熟,无法保证逃逸分析所提高的运行效率能超过它的性能损耗,但是逃逸分析依然是JIT编译器优化技术中一个重要手段

8. TCP粘包问题了解过吗,怎么解决

本题主要考察对TCP协议的了解程度,能回答出来TCP这块基本就不会再问了。一般TCP部分的问题深度由浅至深分别是: TCP/UDP区别 => 三次握手与四次挥手 => 流量控制和拥塞控制 => TCP优化技术与常见问题 ,必须要做好准备

粘包问题有两种常见情况:

  1. TCP协议为了将包更有效地发送到对象,所以使用Nagle优化算法,将多个小数据包合并成大数据块进行封包,因为TCP传输的数据是没有边界的,所以接收方会收到一个粘成一团的包
  2. 接收方没有即时接收消息,导致接收方的TCP缓冲区存放了几段数据,接收方的应用层就会收到不完整的数据

解决方案有两种,一种是只发送固定长度的包,另一种是在发送消息时带上消息的长度,同时使用特殊标记来标记消息边界

9. 为什么主键索引最好是自增的

本题考察的是你的思考能力,如果这题答得不好会给面试官留下只会背题的印象,此题不难,即使不知道答案只要给出自己的想法即可,重点是联系到索引的数据结构上

因为innodb索引采用b+树的结构存储,避免插入非规律主键的数据时,导致页分裂

10. 接口和抽象方法哪一个调用速度快,为什么

本题考察对JVM知识的掌握程度,虽然本题应用意义不大,但是能很好地考察出被面试者对JVM底层原理的了解情况

抽象方法调用速度快,因为抽象类属于实现类的父类,抽象方法的实现属于方法覆写,可以直接根据偏移量来定位方法,而接口则只能通过遍历来找

11. 看下面这段代码,执行结果是什么,为什么

String a1 = new String("a") + new String("a");  // 1
        a1.intern();                                    // 2
        String a2 = "aa";                               // 3
        
        System.out.println(a1 == a2);

        // -------------------------------------
        
        String b1 = new String("b") + new String("b");  // 4 
        String b2 = "bb";                               // 5
        b1.intern();                                    // 6
        
        System.out.println(b1 == b2);
复制代码

本题考察的是面试者对String的理解深度,此题的要点就是能答出intern方法的实现原理,能够完全答对非常难,基本能打趴绝大多数面试者,能够回答出来说明对JVM的常量池很熟悉,绝对是一个加分项,不过遗憾的是基本没有面试官会问这么深

在jdk1.7之前,返回 false false ,在jdk1.7及之后的jdk版本中,返回 true false

为什么在jdk1.7之前返回 false false

  • 因为在jdk1.6中,字符串常量池在“永久代”中,调用String#intern方法时,如果 常量池 中已经存在该字符串对象,会直接返回 常量池 中的对象引用;否则会在 常量池 中创建一个对象,并返回 常量池 中对象的引用
  • 回到代码中, 代码1 在堆中创建了“aa”字符串对象,池中没有“aa”字符串对象; 代码2 发现常量池中没有“aa”对象,则在池中创建“aa”对象; 代码3 发现池中存在“aa”对象,直接返回常量池中对象的引用;此时,a1为 堆中 字符串对象引用,a2为 常量池中 字符串对象引用,显然指向的不是同一个对象
  • 代码4 在堆中创建了“bb”字符串对象,池中没有“bb”字符串对象; 代码5 发现池中没有“bb”对象,则在池中创建“bb”对象; 代码6 发现常量池中存在“bb”对象,不执行操作;此时,b1为 堆中 字符串对象引用,b2为 常量池中 字符串对象引用,显然指向的不是同一个对象

为什么在jdk1.7及之后返回 true false

  • 在jdk1.7中,常量池被存放在Java堆中,jdk1.8中,常量池被放在元空间中,与堆独立(其实主要跟intern方法的实现改变有关,和常量池在哪没有太大关系,所以别被误导了,这一点只是做个知识扩展)
  • 当调用String#intern方法时,如果 常量池 中已经有该对象,则返回 常量池 中对象的引用;否则,将 Java堆 中的 对象引用 添加到 常量池 中,并返回该引用;如果 Java堆 中也不存在,则在 常量池 中创建该字符串对象,并返回其引用
  • 回到代码中, 代码1 在堆中创建了“aa”字符串对象,池中没有“aa”字符串对象; 代码2 发现常量池中不存在“aa”对象,则检查Java堆,发现存在“aa”对象,则将堆中该对象的引用添加到常量池中; 代码3 发现常量池中存在“aa”对象的引用,则返回该引用;此时,a1为 堆中 对象的引用,a2也为 堆中 该对象的引用,指向的是同一对象
  • 代码4/5/6 与jdk1.6中的原理完全一致,就不再赘述了

12. ConcurrentHashMap的扩容是如何实现的

本题考察的是对ConcurrentHashMap源码熟悉程度,答题要点是分区间处理和单节点加锁。如果是考察HashMap的扩容,则答题要点是先创建新数组,再拷贝原数据

  1. 根据处理器个数,计算出每个处理器要处理的区间个数
  2. 创建一个新数组
  3. 计算每个线程需要处理的区间段大小
  4. 遍历每个索引位置,遍历到时对索引节点单个进行加锁
    1. 将索引位置下所有节点分为两个链表,一个是扩容后位置不变的,一个是扩容后位置改变的
    2. 处理完成后将这两个链表一次性放置到原数组对应位置上(使用原子赋值操作,不会影响线程安全)

13. Service Mesh/Serverless是什么

本题主要考察面试者的技术视野,是否仅仅关注自己眼前的技术。这种就属于概念性的问题,能说多少说多少,没有标准答案,能体现出自己有了解过大致的概念即可。这两个问题本身没有太大关联,但是因为都属于这一类问题,不想再单独列出来,就直接放在一起了

  • Service Mesh,指服务网格,属于基础设施层,功能在于处理服务间通信,是系统通信的中间层,负责实现请求的可靠传递。Service Mesh一般由一系列轻量级的网络代理组成,和应用程序部署在一起,但是对应用程序透明(不可见)。可以解耦应用程序的重试、超时、监控、追踪,以及服务发现,让应用服务专注于业务逻辑
  • Serverless,指无服务架构,可以让开发者不用考虑服务器的问题,将计算资源作为服务,而不是服务器。Serverless是一种构建和管理基于微服务架构的完整流程,允许开发者将应用以服务的级别来部署,而不是服务器级别。可以不用去关心服务器运行状态,不用考虑运营维护问题

14. 静态方法和单例模式有什么区别,我们为什么推荐使用单例模式

本题主要考察面试者是否对自己使用的工具有过思考,能够知道“为什么用”,一个工程师至少要清楚自己使用工具的场景,而不能是稀里糊涂的“有就用”

  1. 单例模式契合面向对象的思想
  2. 单例类中的方法可以继承覆写
  3. 单例类可以被延迟实例化
  4. 单例类可以被用于多态,不需要关注全局的状态

15. 伪共享了解吗

本题考察的是面试者对线程安全(特指volatile部分)的掌握程度,如果认真看过JUC包下的源码,就一定会了解到伪共享的概念。不过本题属于加分项,即便不知道也没有太大影响

伪共享指的是两个volatile类型的数据在同一个缓存行中,由于volatile每次都会刷新缓存行,所以导致缓存行没有完全发挥出作用,致使性能浪费

可以通过在对象或字段的前后加padding,也可以使用 @sun.misc.Contended 注解(其原理是在对象或字段前后加上128位的padding)

16. SpringBoot是怎么启动的

本题主要考察对Springboot的了解程度,答题要点是设置监听器和加载上下文,如果这题没答上来或没答好面试官可能会问IoC和AOP原理相关的问题,所以至少有一个要非常熟悉

  • @SpringbootApplication 复合了一些注解:
    • @SpringBootConfiguration :声明该类为配置类
    • @EnableAutoConfiguration :启用自动配置,原理是使用AutoConfigurationImportSelector类,将所有配置类加载到容器中,并扫描配置文件,将配置项通过反射实例化为配置类,汇总之后加载到容器中
    • @ComponentScan :自动扫描包下的bean
  • Springboot在启动时,通过SpringApplication的run方法启动容器。在run方法中,分为两步:
    1. 先构建SpringApplication对象,其中会设置成员变量和监听器,最终推断main方法所在的入口类
    1. 然后调用SpringApplication具体实例对象的run方法,会遍历并启动监听器,封装args参数为对象,初始化并加载应用上下文

17. 适配器模式的应用场景是什么,举几个具体应用的例子

本题主要考察对适配器这种设计模式的掌握程度,现在很多人为了突击面试,设计模式只看过单例和工厂两种,如果问到其他设计模式答不上来,会在面试官的心中大打折扣

应用场景:

  • 需要使用某个类,但是接口不符合需要
  • 需要将一些没有公共接口/父类的类关联起来,使其可以一起工作
  • 需要为一些类提供统一的输出接口

应用实例:

  • spring-aop:将不同的通知类型适配到统一的适配器接口AdvisorAdapter中,可以通过具体的适配器类来获取对应通知的拦截器
  • spring-mvc:使用HandlerAdapter来适配具体的Controller,实现了DispatcherServlet和Controller之间的统一接口对接

18. CountDownLatch的await()方法有什么风险

本题主要考察面试者是否真正用过CountDownLatch,是否在使用时有考虑过风险。与此题类似的问题还有: ThreadLocal 使用时需要注意什么, SimpleDateFormat 在多线程下使用有什么风险等

如果执行countDown的线程发生异常,则await()方法会被阻塞。所以要设置超时时间,即使用 await(timeout, unit) 方法

19. 为什么有些公司弃用zookeeper

本题主要考察对zookeeper的掌握程度,能说出一种工具的优点很容易,有时候编也能编个差不多,但是想说出来缺点就需要对它有相当的了解才行。如果是校招的话一般不会问这么深,回答不上来也不用太紧张,但是一定要敢于说出来自己的见解,即使是错的

客户端:

  • 服务端集群的地址列表是写死在客户端的,不支持动态变更
  • 不支持同机房优先策略
  • 没有针对服务端集群完全不可用的容灾策略

服务端:

  • 写能力不足,不支持水平扩展
  • 监测手段单一,只有TCP的活性监测

20. Java中基本数据类型是对象吗

本题考察的是对Java语言的理解程度,这个问题几乎没见过有面试官问过,问题本身的价值也不是很大,如果答不上来也没有太大关系,不过确实能反应出面试者对语言的认识程度

JVM会把所有的基本数据类型当作对象处理,JVM有9种设定好的Class对象来对应 基本数据类型void关键字 ,这些对象都是JVM创建的

除了基本类型之外,枚举也是一种类,注解属于一种特殊的接口,数组也是Object的子类,但是对程序员是透明的

原文  https://juejin.im/post/5d6a222a6fb9a06b1777ccdc
正文到此结束
Loading...