概述
最近投了很多中型的互联网企业分享一下最近的一次面试,全程下来感觉有点别扭和反感,问题更偏向实战和一些他们认为开发中常见的问题。
背景
形式: 现场笔试 + 三轮面(一下午)。
轮次: 组长+部门领导、HR面,后续有一个更大的领导面
职位: 中级Java开发
薪资范围: 12-18K
笔试
去了先来一套笔试题大概三四页,具体的题记不太清楚了更多是偏向基础的。
1. 给定了一段代码考察String类型的传递类型,和对象内String属性的传递类型,写出输出结果
2. 写出java中的有序集合 - ArrayList、LinkedList、Vector、CopyOnWriteArrayList - TreeSet - PriorityQueue - SortedSet接口及其实现
3. 输出数组元素的方式
- for循环遍历、for-each循环便利、Arrays类的toString方法
4. HashMap的遍历方式
entrySet()遍历键值对keySet()遍历键,通过键获取值values()遍历值- Stream API遍历
5. switch支持的数据类型
- 基本数据类型:byte short int char
- 枚举类型:JDK1.5之后
- String类型:JDK1.8之后
6. 抽象类和接口是否可以被序列化
- 抽象类和接口本身不能被序列化,抽象类和接口的实现类(即具体的子类)可以被序列化实现Serializable接口
7. 给了一段代码考察 @Transactional的知识,大概就是在不同的位置抛出异常输出什么。
- 这个如果大家遇到要看清楚调用的方法是否被spring容器管理,其实变相考察spring事务的实效方式
8. @Component和@Bean的区别
- 作用对象:
- @Component注解作用于类,表明该类是一个Spring组件,Spring会自动扫描该类,并将其实例化为一个Bean,然后将其放入Spring容器中管理。
- @Bean注解则作用于方法,在标有该注解的方法中定义并返回一个对象,这个对象会被注册为Spring容器中的Bean。
- 注册方式
- @Component通常是通过路径扫描来自动侦测以及自动装配到Spring容器中。我们可以使用@ComponentScan注解定义要扫描的路径,从中找出标识了需要装配的类,然后自动装配到Spring的Bean容器中。
- @Bean注解则是通过显式地在方法上标注,并返回需要注册的Bean对象。这种方式提供了更大的灵活性,特别是在需要引用第三方库中的类或者进行更复杂的Bean定义时。
- 自定义性
- @Bean注解的自定义性更强。在很多情况下,我们只能通过@Bean注解来注册Bean,比如当我们需要引用第三方库中的类并装配到Spring容器时。
- @Component注解作用于类,表明该类是一个Spring组件,Spring会自动扫描该类,并将其实例化为一个Bean,然后将其放入Spring容器中管理。
9. Spring是通过byName还是byType的方式进行注入的?如果有相同的Name或相同的Type如何解决?会抛出什么异常?
-
byName: 当使用byName方式进行注入时,Spring会在应用上下文中查找与属性名相匹配的bean。例如,如果你有一个名为
dataSource的属性,Spring会尝试找到一个名为dataSource的bean来进行注入。 -
byType: 当使用byType方式进行注入时,Spring会查找与属性类型相匹配的bean。如果找到多个相同类型的bean,Spring会抛出一个异常,因为它不知道应该注入哪一个。
-
对于相同的Name:
- 如果两个或多个bean有相同的名称,Spring会抛出一个异常,你需要确保每个bean都有一个唯一的名称,或者使用其他方式(如Qualifier注解)来明确指定要注入的bean。
-
对于相同的Type:
- Spring会抛出一个
NoUniqueBeanDefinitionException。 - 你可以使用
@Qualifier注解来指定应该注入哪一个bean。
- Spring会抛出一个
10. 如何理解多态
- 多态描述的是完成某个行为时,当不同的对象去完成会产生出不同的状态。多态建立在继承和封装的基础上。多态有三种实现方式:接口、重写、抽象。多态的主要作用包括:提高代码的维护性(由继承保证)。提高代码的扩展性(由多态保证)。屏蔽不同子类对象之间的差异,使得可以把不同的子类对象都当作父类来看,写出通用的代码,做出通用的编程,以适应需求的不断变化。
11. SpringCloud配置的加载顺序
- /config/application
- /application
- 配置中心
一面
一面是一个面试官面我们呢两个人,大概看了下我们的简历和期望薪资和我们说:我要的多让另一个先回答我补充。然后是按照另一个人的技术栈问问题。全程几乎没有介绍项目环节,有的问题没理解。我更多的是补充另一个人说的。最后和我们两个说问的比较基础都是开发中遇到的,深入的像CurrentHashMap如何扩容这种还没开始问。
1. 手写过连接池吗?
哥们啥家庭要手写连接池啊,我们两个都没写过。
2. stream流如何将一个集合内的人员信息分组key为部门,value为HashMap,value内的HashMap的key为职位,value为人员的具体信息。
Map<String, Map<String, List<Person>>> groupedByDepartmentAndPosition = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment, // 按部门分组
Collectors.groupingBy(Person::getPosition) // 每个部门内部再按职位分组
));
3. 项目中用到了maven,如果maven第一行出现了红线无法运行什么原因导致的?
- 网络问题
- pom文件错误
- 本地仓库问题
- 插件或版本冲突
- 项目依赖问题
- IDEA配置问题
4. 看你写的熟悉多线程开发如果现在有一个场景ABC三个线程,要求是A线程先执行,BC等待,A结束后ABC再同时执行可以用什么锁实现?
- 另一个小伙子回答的用redis锁,面试官说用java锁实现,我回答的ReentrantLock,他说也不对ReentrantLock只能锁单个资源。我有点懵这个感觉回答的没问题。
5. 线程池的创建方式、使用ThreadPoolExecutor方式创建线程池参数有哪些?线程工厂有哪几种?
-
创建线程的方式可以分为两类:
Executors工厂类、ThreadPoolExecutor类。 -
线程池参数
- corePoolSize(核心线程数):线程池中的核心线程数,即使这些线程处于空闲状态,也不会被销毁。除非设置了
allowCoreThreadTimeOut。 - maximumPoolSize(最大线程数):线程池允许的最大线程数。当队列满了,且已创建的线程数小于最大线程数时,会创建新线程来处理任务。
- keepAliveTime(线程空闲时间):当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。
- TimeUnit(时间单位):
keepAliveTime参数的时间单位,例如TimeUnit.SECONDS。 - BlockingQueue (工作队列):用于保存等待执行的任务的阻塞队列。
- ThreadFactory(线程工厂):用于创建新线程的工厂,通常使用默认的即可。
- RejectedExecutionHandler(拒绝策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略由
RejectedExecutionHandler接口的实现类决定。
- corePoolSize(核心线程数):线程池中的核心线程数,即使这些线程处于空闲状态,也不会被销毁。除非设置了
-
线程工厂
ThreadFactory是一个接口,Java标准库并没有提供太多现成的实现,但你可以根据需要自定义实现。通常使用默认的线程工厂Executors.defaultThreadFactory()
6. Redis和MySql如何在高并发下保证数据一致性?延迟双删为什么要第二次删除?在读线程中更新redis之前并发量非常高的情况下会有什么问题?
这个问题比较复杂简单来说可以分为两个方向去回答,这里只给出大体思路实际还是要根据实际的业务出发去回答:
-
最终一致性
- 通过事务消息进行补偿
- 通过canal去监听mysql数据库,当数据变更进行更新redis
-
强一致性
强一致性会导致程序性能降低,延迟双删数据更新时可以加锁强制部分请求等待,默认先查询,有则返回数据、无则加锁。加锁后还是先查redis,有则返回,无则查询mysql更新redis
7. 抽象类能否被spring容器管理,或者怎么做可以被它管理?如果没有实例化会抛出什么异常
抽象类本身不能被Spring容器直接实例化,因为抽象类不能被实例化。Spring容器可以管理抽象类的子类,只要这些子类是可实例化的。NoSuchBeanDefinitionException 异常
8. SpringBoot对外提供接口如何保证非正常情况下异常不会抛出。注意:不包含前端的操作,其他服务调用提供的接口不收到的Exception。
-
全局异常处理(@ControllerAdvice)
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = Exception.class) @ResponseBody public ResponseEntity<ErrorResponse> handleException(Exception e) { ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } // 可以添加更多的@ExceptionHandler方法处理特定类型的异常 } -
自定义异常类
创建自定义异常类封装特定业务中的异常,通过全局异常处理捕获
-
使用Spring的@ResponseStatus注解
对于某些特定的异常,可能希望直接定义HTTP状态码,而不是在全局异常处理器中处理。可以使用
@ResponseStatus注解在自定义异常类上定义HTTP状态码。 -
API网关的异常处理
9. Spring除了一些常用接口中的注解、事务、注册Bean你还用它做过什么?
- 集成web应用开发
- 通过AOP实现日志记录、事务管理等
- Spring Test
10. SpringBoot如何实现的按需加载
这里主要提了一下@ConditionalOnProperty、@ConditionalOnClass、@ConditionalOnMissingBean,这些注解允许你根据条件动态地创建或排除 Bean。
11. 在SpringBoot项目中如何动态加载一个外部jar,注意这个包不是一个类似hutool工具类而是一个服务。
没理解这个问题
12. 在Mybatis中写一个查询语句,这个语句中有一个字段为性别存储的为0或1,这个值在字典表中有相应的解释。不使用连接查询以及分别查询两表数据遍历赋值的方式,还有没有其他实现方法。
这块仔细想一下好像不管什么方法都需要查数据遍历,面试官有可能考察的是不包含在应用层进行数据遍历。
- 通过Mybatis 的 TypeHandler,然后在resultType中进行转换
- 通过Mybatis插件,也就是自己写一个拦截器,这种方法其实就更复杂了
- 我在开发过程中用的更多的其实是定义枚举类型
后面的问题主要问的我
-
mysql中有一个带有where条件的连接查询,但是没有走索引为什么?你还知道那几种不走索引的情况?
没有走索引的原因:
- 使用了select *,这个问题很
- where条件中或连接查询的条件的值类型不匹配或隐式转换
- 使用了or、!=、not in、like + 前面使用了通配符
- 使用了聚合函数
- 强制索引
-
selec语句只查询一个列,且where条件中只有一个条件,该条件为联合索引中的字段,一定会命中索引吗?
不一定会命中索引,联合索引其实是一个组合索引假设ABC三个字段的联合索引其实是加的A、AB、ABC,如果使用了B查询则不会走索引。这里不考虑一些特殊情况了。
-
你是在什么场景下用到了CompletableFuture?他的方法有返回值吗?如果在异步编排后需要等待他的结果,调用join或allOf和get会占用cpu吗?
CompletableFuture提供的部分方法是有返回值的,为CompletableFuture对象可以通过get()获取,例如thenApply()、thenAccept()、thenRun()等。
调用
allOf()方法返回的CompletableFuture对象的get()或join()方法,并且还有未完成的异步操作,那么这些方法会阻塞当前线程,直到所有异步操作都完成。 -
问另一个人nacos作为配置中心如何设置动态刷新配置
- 使用@RefreshScope注解实现动态刷新
- 使用Nacos的ConfigListener接口**:通过实现Nacos的ConfigListener接口,你可以监听配置的变化,并在配置变化时执行相应的刷新逻辑。
- 使用Nacos的@NacosConfigurationProperties注解**:这个注解可以帮助你自动绑定Nacos的配置到Spring Bean中,当配置变化时,Spring Bean也会自动更新。
-
问我Appllo删除配置后程序中如何感知到
- @Value注解结合@RefreshScope
- 配置ConfigChangeListener监听器
- 手动触发刷新:ConfigService.getAppConfig()
-
MQ如何保证消息可靠性
这个问题就不详细讲了,可以去看以下这篇文章 https://juejin.cn/post/7353087310109982730
-
ES用的什么分词器?如何开发的相关功能
这个建议大家详细了解一下es的中分分词器就可以
-
为什么用Redis+Caffeine,还知道哪些分布式系统应用级别的缓存?
回答了Redis和memecache他说不对,也没理解到底啥意思。
-
SpringCloud如果要对外提供服务,那调用方除了会用到jar里面的参数实体还有什么服务?
个人一直没理解这个问题。面试官说这个不挺简单吗rpc框架已经实现了。
二面:部门领导+HR
二面应该是部门的领导单独面,HR进来旁听后来HR直接问问题了
HR:
- 详细介绍一下自己的履历从上学到工作
- 在哪上的学考了多少分
- 父母在哪、干的什么工作、是否在北京置业
- 提问工作经历怎么去的第一家公司、各个阶段的离职原因、公司主营业务和公司规模、开发团队规模,是否包含了领导
- 社保流水是不能可以提供
- 当前是否离职、离职时间,我是2月底离职的她问为什么最近才投简历
- 是否有offer、为什么没去,有家公司offer给不了那么高有没有想过自己的原因,考虑降低期望薪资吗
- 为什么来我们公司
部门领导
- 自我介绍
- 假设有一个业务从A银行给B银行转账你怎么设计
- 项目中主要做了什么、公司项目数据量多大
- 你们的购物车如果涉及商品价格变动如何实现的,有什么优化方案
- 你是在什么场景下用到了CompletableFuture
- 如何开发的秒杀活动、需要注意什么
- 介绍一下项目中的优惠券、活动以及相关促销模块最终到下单的设计思路
- 如果和产品的需求理解有冲突是不是会有情绪
- 最近看的几本书
- 英文水平,能否看懂英文文档
- 未来3-5年的规划
#反问
由于后面部门领导出去了没有问技术架构,只能问HR问题
-
当前岗位的方向和开发团队
-
薪资构成和福利
-
是否加班、有没有调休
-
晋升和涨薪
总结
最后面完之后HR说给不了想要的期望薪资,部门内现在有的同级别的开发薪资范围是10-15K,其实最高只能给15,如果可以接受就约公司的领导进行终面如果不能接受提前和他沟通是否终止。
个人认为笔试虽然比较偏基础但是题型还是有点别扭的,题量不是很多应该也没有时间限制,反正我写了不到20分钟。
第一位面试官更多是根据另一个人的简历提问问题,然后我补充,有一些问题没太理解,一部分好像是更偏向他们自己遇到过的问题。反正我很少遇到spring引入别人的服务jar,还有SpringCloud对外提供一般都是接口不知道他问的服务是什么意思。后来给我们两个的总结是另一个人回答的是皮毛,我回答的都是只对了一半。
第二位面试官面的更多是场景设计题中规中矩吧。
HR提问全程感觉有压迫感而且还有pua的味道,第一个问题他说我回答的比其他面试者好,HR说我肯定有一定的经验或者是做过相关项目。然后公司有必要了解那么详细吗从多少个开发人员到主营业务啥都问,还会用她自己的理解描述出你做的东西让你自己都感觉很简单。父母的职业和家庭情况问的太仔细了。薪资既然给不了那么高boss上还标的范围那么大,然后标的补贴我问她的时候也没有提及。
反正这次面试感觉非常别扭很多问题感觉很偏,写出来给大家找个乐子。