《互联网大厂Java面试:核心知识大考验》

43 阅读6分钟

面试官:请简要介绍一下Java核心知识中的面向对象三大特性。

王铁牛:这个简单,就是封装、继承和多态嘛。

面试官:不错,回答正确。那再说说JUC中常用的并发工具类有哪些。

王铁牛:像CountDownLatch、CyclicBarrier、Semaphore这些。

面试官:很好。接下来谈谈JVM的内存模型。

王铁牛:呃……这个嘛,就是堆、栈、方法区这些吧。

面试官:回答得不是很清晰,再仔细讲讲。

第一轮结束。

面试官:多线程中如何实现线程安全?

王铁牛:可以用synchronized关键字或者Lock接口。

面试官:那线程池的核心参数都有哪些?

王铁牛:有corePoolSize、maximumPoolSize、keepAliveTime这些。

面试官:说说HashMap的底层数据结构。

王铁牛:好像是数组加链表,哦不,还有红黑树。

面试官:回答得不太准确,再好好想想。

第二轮结束。

面试官:ArrayList的扩容机制是怎样的?

王铁牛:每次扩容是原来的1.5倍。

面试官:Spring框架中依赖注入的方式有哪些?

王铁牛:构造器注入、setter方法注入。

面试官:Spring Boot的启动流程了解吗?

王铁牛:这个不太清楚。

面试官:那说说MyBatis的缓存机制。

王铁牛:有一级缓存和二级缓存。

第三轮结束。

面试结束,面试官表示会让王铁牛回家等通知。

答案:

  1. 面向对象三大特性
    • 封装:将对象的属性和行为包装在一起,对外提供统一的接口,隐藏内部实现细节,提高代码的安全性和可维护性。
    • 继承:子类继承父类的属性和方法,实现代码复用,提高开发效率。
    • 多态:同一个行为具有多种不同表现形式,通过父类引用指向子类对象,在运行时根据对象的实际类型调用相应的方法,增强代码的灵活性和扩展性。
  2. JUC常用并发工具类
    • CountDownLatch:用于线程间的同步,它允许一个或多个线程等待其他一组线程完成操作。通过构造函数传入一个计数值,调用await方法的线程会阻塞,直到计数值为0。其他线程通过调用countDown方法来减少计数值。
    • CyclicBarrier:也用于线程同步,它允许一组线程互相等待,直到到达某个公共屏障点。与CountDownLatch不同的是,CyclicBarrier可以重用,当所有线程到达屏障点后,屏障会重置,可继续下一轮的同步。
    • Semaphore:信号量,用于控制同时访问某个资源的线程数量。通过构造函数传入许可数量,线程调用acquire方法获取许可,调用release方法释放许可。
  3. JVM内存模型
    • :是Java虚拟机所管理的内存中最大的一块,被所有线程共享,用于存放对象实例。
    • :每个线程都有自己独立的栈空间,用于存储局部变量、方法调用等。
    • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量等数据。
  4. 多线程实现线程安全
    • synchronized关键字:可以修饰方法或代码块,当一个线程访问被synchronized修饰的方法或代码块时,会先获取对象的锁,其他线程必须等待该锁被释放后才能访问。
    • Lock接口:提供了比synchronized更灵活的锁控制,如可中断锁、公平锁等。通过Lock接口的实现类如ReentrantLock来实现线程安全。
  5. 线程池核心参数
    • corePoolSize:线程池的核心线程数,当提交的任务数小于corePoolSize时,线程池会创建新线程来执行任务。
    • maximumPoolSize:线程池允许的最大线程数,当提交的任务数大于corePoolSize时,会将任务放入队列中,如果队列已满且线程数小于maximumPoolSize,则会创建新线程来执行任务。
    • keepAliveTime:线程池中非核心线程的存活时间,当线程空闲时间超过keepAliveTime时,非核心线程会被销毁。
  6. HashMap底层数据结构
    • 在JDK 1.8之前,HashMap底层是数组加链表结构。当插入元素时,通过计算key的哈希值得到数组下标,如果该下标对应的位置为空,则直接插入;如果不为空,则采用链表头插法插入新元素。
    • 在JDK 1.8之后,HashMap底层数据结构变为数组 + 链表 + 红黑树。当链表长度大于8且数组长度大于64时,链表会转换为红黑树,以提高查询效率。
  7. ArrayList扩容机制
    • ArrayList默认初始容量是10。当添加元素导致容量不足时,会进行扩容。每次扩容是原来容量的1.5倍。扩容时会创建一个新的更大的数组,将原数组中的元素复制到新数组中。
  8. Spring框架依赖注入方式
    • 构造器注入:通过构造函数来注入依赖对象,这种方式可以保证依赖对象在对象创建时就被注入,并且一旦注入完成,对象就处于完整可用状态。
    • setter方法注入:通过setter方法来注入依赖对象,这种方式更加灵活,对象创建时可以不注入依赖,后续再通过setter方法进行注入。
  9. Spring Boot启动流程
    • Spring Boot应用启动时,首先会创建SpringApplication实例。
    • SpringApplication会根据应用的类型(如Web应用等)进行相应的初始化配置。
    • 然后通过调用run方法启动应用,在run方法中会进行一系列操作,包括创建Spring容器(如AnnotationConfigApplicationContext或AnnotationConfigServletWebServerApplicationContext)。
    • Spring容器会扫描应用中的组件,通过注解(如@Component、@Service等)将这些组件注册到容器中,并根据依赖关系进行自动装配。
    • 最后,Spring Boot会启动内置的Web服务器(如Tomcat),监听指定端口,处理客户端请求。
  10. MyBatis缓存机制
  • 一级缓存:是SqlSession级别的缓存,在同一个SqlSession中,对相同的SQL语句进行查询时,会直接从缓存中获取数据,不会再次查询数据库。当SqlSession关闭时,一级缓存会被清空。
  • 二级缓存:是基于namespace级别的缓存,多个SqlSession可以共享二级缓存。当一个SqlSession查询数据时,会先从一级缓存中查找,如果没有则从二级缓存中查找,若二级缓存也没有则查询数据库,并将查询结果放入一级缓存和二级缓存中。二级缓存需要在MyBatis配置文件中进行配置启用。