《揭秘互联网大厂Java面试:从基础到进阶的核心知识点大考察》

47 阅读9分钟

第一轮面试 面试官:先来聊聊Java基础。讲讲Java中ArrayList和HashMap的区别。 王铁牛:ArrayList是有序的,按顺序存放元素,像排队一样。HashMap是无序的,通过键值对存储数据,查找数据快。 面试官:回答得不错。那HashMap在JDK1.7和JDK1.8中有什么主要区别? 王铁牛:嗯……1.8好像优化了哈希冲突处理,用了红黑树,1.7好像是链表。 面试官:可以。那ArrayList扩容机制是怎样的? 王铁牛:当元素个数达到容量时,会扩容为原来的1.5倍,然后把旧数据复制到新数组。

第二轮面试 面试官:接下来谈谈多线程和JUC。讲讲线程池的核心参数有哪些? 王铁牛:有核心线程数、最大线程数,还有队列容量。 面试官:很好。那线程池的工作原理是怎样的,结合这些参数说一下。 王铁牛:嗯……任务来了先看核心线程有没有满,满了就放队列,队列满了就看最大线程数,要是还不行就拒绝策略。 面试官:那常见的拒绝策略有哪些? 王铁牛:有直接拒绝,还有……还有那个什么丢弃最老任务。

第三轮面试 面试官:最后说说框架相关。Spring和Spring Boot有什么关系? 王铁牛:Spring Boot是基于Spring的,简化了Spring的配置,能快速搭建项目。 面试官:那MyBatis在项目中主要解决什么问题? 王铁牛:它主要解决数据库操作,像SQL语句的编写和映射。 面试官:Dubbo在微服务架构中有什么作用? 王铁牛:嗯……好像是做服务治理,服务的注册和发现。 面试官:RabbitMQ在项目中一般用于什么场景? 王铁牛:消息队列嘛,异步处理,削峰填谷。 面试官:xxl - job在项目里主要用途是什么? 王铁牛:是做任务调度的,能定时执行任务。 面试官:Redis有哪些常见的数据类型,在项目里一般怎么用? 王铁牛:有字符串、哈希、列表……项目里可以存缓存数据。

面试总结:通过这三轮面试,我们考察了你在Java核心知识、集合框架、多线程、线程池以及常见框架和中间件等方面的知识。在一些基础问题上,你回答得还不错,展现了一定的知识储备。但在一些稍微深入的问题上,回答得还不够清晰和全面,对技术原理和业务场景的理解还有待加强。我们后续会综合评估所有面试者的情况,你先回家等通知,无论结果如何,希望你能继续提升自己的技术能力,不断学习进步。

问题答案

  1. ArrayList和HashMap的区别
    • 存储结构:ArrayList是基于数组实现的,有序存储元素,元素可以重复;HashMap是基于哈希表实现的,以键值对形式存储,键不能重复,无序存储。
    • 查找效率:ArrayList查找元素需要遍历数组,时间复杂度为O(n);HashMap通过哈希算法计算键的哈希值定位存储位置,理想情况下时间复杂度为O(1)。
    • 应用场景:ArrayList适合需要顺序访问元素的场景,如遍历列表;HashMap适合根据键快速查找值的场景,如用户信息通过ID查找。
  2. HashMap在JDK1.7和JDK1.8中的主要区别
    • 数据结构:JDK1.7中HashMap采用数组 + 链表结构,当哈希冲突时,以链表形式存储;JDK1.8中当链表长度大于8且数组容量大于64时,链表会转换为红黑树,提高查找效率。
    • 哈希算法:JDK1.8的哈希算法更优化,减少了哈希冲突的概率。
    • 扩容机制:JDK1.7扩容时,需要重新计算哈希值和复制数据;JDK1.8在扩容时,部分数据可以直接迁移,减少了数据迁移的开销。
  3. ArrayList扩容机制
    • ArrayList有一个默认初始容量,一般为10。当向ArrayList中添加元素时,如果当前元素个数达到了容量大小,就会触发扩容。
    • 扩容时,新的容量为原来容量的1.5倍(通过位运算实现,即原容量左移一位再加原容量)。然后创建一个新的数组,将原数组中的数据复制到新数组中。
  4. 线程池的核心参数
    • 核心线程数(corePoolSize):线程池中常驻的线程数,即使这些线程处于空闲状态,也不会被销毁。
    • 最大线程数(maximumPoolSize):线程池中允许存在的最大线程数。当任务队列已满且核心线程都在忙碌时,会创建新线程,直到达到最大线程数。
    • 队列容量(workQueue):用于存放等待执行任务的队列。常见的队列类型有ArrayBlockingQueue(有界队列)、LinkedBlockingQueue(无界队列)等。
    • 线程存活时间(keepAliveTime):当线程数大于核心线程数时,多余的空闲线程等待新任务的最长时间,超过这个时间就会被销毁。
    • 时间单位(unit):线程存活时间的单位,如TimeUnit.SECONDS(秒)。
  5. 线程池的工作原理
    • 当有新任务提交到线程池时,首先判断核心线程数是否已满。如果核心线程数未满,就创建新的核心线程来执行任务。
    • 如果核心线程数已满,任务会被放入任务队列中等待。
    • 如果任务队列也已满,再判断最大线程数是否已满。如果最大线程数未满,就创建新的非核心线程来执行任务。
    • 如果最大线程数也已满,就会根据设定的拒绝策略来处理新任务。
  6. 常见的拒绝策略
    • AbortPolicy(直接拒绝):这是默认的拒绝策略,当任务无法处理时,直接抛出RejectedExecutionException异常。
    • CallerRunsPolicy(调用者运行):将任务交给调用execute方法的线程来执行,这样可以降低新任务的提交速度。
    • DiscardPolicy(丢弃任务):直接丢弃无法处理的任务,不抛出异常。
    • DiscardOldestPolicy(丢弃最老任务):丢弃任务队列中最老的任务(即队列头部的任务),然后尝试将新任务加入队列。
  7. Spring和Spring Boot的关系
    • Spring是一个开源的Java应用框架,提供了依赖注入(DI)、面向切面编程(AOP)等功能,帮助开发者构建企业级应用。但Spring配置较为繁琐,需要大量的XML配置文件或Java配置类。
    • Spring Boot是基于Spring构建的,它的目标是简化Spring应用的初始搭建和开发过程。Spring Boot采用“约定大于配置”的原则,默认提供了很多配置,开发者只需很少的配置就能快速搭建一个Spring应用,专注于业务逻辑开发。
  8. MyBatis在项目中主要解决的问题
    • 数据库操作简化:MyBatis提供了一种简单的方式来执行SQL语句,将Java对象和数据库表进行映射。开发者只需编写SQL语句,MyBatis负责将参数传入SQL并处理结果集。
    • SQL语句管理:可以将SQL语句集中管理在XML文件或注解中,便于维护和修改。同时支持动态SQL,根据不同的条件生成不同的SQL语句。
    • 提高开发效率:避免了传统JDBC开发中大量的样板代码,如获取连接、创建Statement、处理结果集等,提高了开发效率。
  9. Dubbo在微服务架构中的作用
    • 服务注册与发现:Dubbo提供了服务注册中心(如Zookeeper、Nacos等),服务提供者将自己的服务注册到注册中心,服务消费者从注册中心获取服务地址,实现服务的动态发现和调用。
    • 负载均衡:当有多个服务提供者提供相同服务时,Dubbo可以实现负载均衡,将请求均匀分配到各个服务提供者上,提高系统的可用性和性能。
    • 服务治理:Dubbo支持对服务进行监控、限流、降级等治理功能,保障微服务架构的稳定运行。
  10. RabbitMQ在项目中的常见场景
  • 异步处理:将一些耗时的操作(如发送邮件、生成报表等)放入消息队列,主线程继续执行其他任务,提高系统的响应速度。
  • 削峰填谷:在高并发场景下,将大量请求放入消息队列,避免瞬间高流量对系统造成压力,系统按一定的速率从队列中取出任务处理,起到削峰填谷的作用。
  • 解耦系统:不同模块之间通过消息队列进行通信,降低模块之间的耦合度,提高系统的可维护性和扩展性。
  1. xxl - job在项目里的主要用途
  • 任务调度:xxl - job是一个分布式任务调度平台,可用于定时执行任务,如每天凌晨备份数据库、定时清理过期数据等。
  • 分布式任务管理:支持集群部署,能够管理多个节点上的任务,实现任务的分布式执行,提高任务处理能力。
  • 任务监控与报警:提供任务执行情况的监控功能,当任务执行失败时可以发送报警通知,方便开发者及时处理问题。
  1. Redis常见的数据类型及在项目中的应用
  • 字符串(String):最基本的数据类型,可用于存储简单的文本、数字等。在项目中常用于缓存用户信息、配置参数等,如缓存用户登录信息,以用户ID为键,用户信息为值。
  • 哈希(Hash):用于存储对象,以字段和值的形式存储。适用于存储结构化数据,如用户的详细信息,每个字段对应一个属性。
  • 列表(List):按插入顺序有序存储元素,可用于实现消息队列、排行榜等功能。如实现简单的消息队列,生产者向列表中添加消息,消费者从列表中取出消息。
  • 集合(Set):无序存储不重复元素,可用于实现标签功能、去重等。如统计网站的独立访客,将访客ID存入集合,利用集合的去重特性统计访客数量。
  • 有序集合(Sorted Set):与集合类似,但每个元素都关联一个分数,根据分数排序。常用于实现排行榜功能,如游戏玩家的积分排行榜。