Java面试进阶篇(1)

0 阅读20分钟

老杨|十年大厂 Java 实战经验,专注技术干货分享!本文整理高频考点与思路,希望能帮到正在面试的你。

问答1:自我介绍

面试官:你好,欢迎来参加今天的面试,请先自我介绍下。
面试者:你好!我叫 xxx,做 Java 后端开发有 x 年了,在上家公司负责订单中心的开发与优化,高并发微服务和性能调优。主导过分库分表改造,把大促接口响应从 200ms 优化到 50ms 以内;也做过秒杀防超卖,解决过 JVM 频繁 Full GC 这类线上问题,扛住了单场 10 万 TPS 的大促流量压力。我擅长从业务痛点出发做性能攻坚和系统稳定保障,非常期待能加入贵公司,贡献自己的实战经验。
分析思路

  • 考点:1、表达逻辑清晰,能快速提炼核心竞争力,突出高并发、性能调优两大优势;2、项目复杂度与技术深度匹配中高级 Java 岗位,具备分库分表、秒杀优化、JVM 调优等实战经验;3、技术定位明确,聚焦后端专项能力,不泛泛而谈。
  • 注意:表述务实不夸大,重点突出可量化成果与真实线上问题解决能力,便于面试官后续针对性深挖验证。

问答2:服务器CPU突然飙高排查方法

面试官: 你的系统CPU突然飙高,你通常怎么排查?用什么命令?

面试者: 会快速把服务器的相关指标记录下来,如果严重影响业务,立刻隔离下线,流量负载到其它服务,保障服务可用。主要是top命令,查看cpu、内存使用情况,其中看四个核心指标可以确定问题的大方向。

  1. us(用户态cpu):超过70%,则推断可能用户进程占用的cpu在进行密集型的开销,使用jstat,优先查看垃圾回收情况,是否有频繁的、耗时的FULLGC。如果GC没有问题,在通过top -h PID命令查看cpu占用最高的进程下的线程,使用jstack查看是否是死循环、锁竞争、正则回溯、复杂计算、日志打印等(可以借助Arthas快速定位)。解决方案:紧急优化(如降低日志级别、临时调整 JVM 参数),后续JVM 调优、代码算法等优化。(GC有问题)必要时导出堆内存快照使用eclipse mat工具分析,要注意可用磁盘空间是否足够。
  2. sy(内核态cpu):超过30%,推断可能是线程过多频繁切换,锁竞争大,频繁IO操作。可以使用vmstat查看上下文切换情况,线程数是否远超cpu核心数。解决方案是:线程池调优 + 锁粒度拆分 + IO 改批量/异步。
  3. wa(IO等待cpu):超过20%,推断磁盘IO打满,可能数据库慢查询、redis、三方接口等阻塞。使用iostat命令查看磁盘读写情况是否接近100%,再使用iotop命令找出占用最大的进程或线程。解决方案:根据进程/线程,定位到瓶颈(磁盘/数据库/网络),非核心业务紧急停止,再针对性减少IO次数,提升IO效率进行优化。
  4. si(软中断cpu):超过20%,推断网卡流量打满,大量小包收发。使用sar命令查看网卡流量和数据包,如果每秒收发几十万,说明大量小包导致了软中断,很可能是tcp短连接频繁创建和关闭,使用ss -antp 查看tcp连接状态。解决方案:优化内核tcp参数,调整TIME_WAIT回收策略、扩容带宽、开启网卡多队列等,也有可能是dos攻击,开启防火墙封禁ip。
  5. 其他排查:也有可能是内存爆了引起的cpu爆,内存不足会使用物理内存进行数据交换,cpu在操作Swap数据相比内存非常低效,生产环境必须要关掉禁用Swap。如果cpu长时间100%但是top里面看不到高cpu的进程,或者是陌生进程,很有可能是被挖矿入侵,这种情况一般就要防扩散重装系统了(就像到了癌症晚期,必须得换器官才能根治。‘疏解下紧张的氛围,一句话就够’)。如果是规律性的cpu飙升,检查是否有定时任务在跑,比如数据库备份等。(如果是硬中断异常,一般是网卡磁盘等硬件有问题,但这种概率很小。)

分析思路

  • 考点:系统级性能分析能力,熟练使用命令行工具。
  • 注意:避免在高峰期直接jstack(可能阻塞),优先用pidstat -u 1实时监控;Windows环境下使用进程资源管理器+ProcDump更高效。
  • 代码示例
# 使用命令
top // 查看系统总体用情况
top - H -p PID // 进程内的所有线程
vmstat 1 5 // CPU上下文切换、中断、内存/交换分区使用情况
jstat -gcutil PID 1000 // 查看进程的GC回收情况
jstack -l PID > jstack_$(date +%Y%m%d_%H%M%S).log // 输出线程栈(间隔3秒记录3次)
iostat -x 1 5 // 磁盘整体使用率、响应、读写
iotop -o // io占用实时情况,按p切换进程和线程、按a切换实时和累积
sar -n DEV 1 // 查看网卡流量,软中断si高的定位排查
watch -d -n 1 cat /proc/softirqs // 查看软中断类型,是否网络相关
ss -antp // 服务器网络端口连接查看

问答3:姓名右匹配查询的数据库设计

面试官: 假设业务需要查询姓名以"晓明"结尾或以"刘晓"开头的用户,如何保证查询效率?

面试者: 采用反向存储+前缀索引方案:在数据库中存储姓名的反转字符串,并创建B-tree索引。将右匹配条件反转为前缀匹配,利用B-tree索引加速。如果数据量特别大,需要专用搜索引擎(Elasticsearch),将姓名数据同步到 ES,利用 ES 的倒排索引和分词器优化前缀/后缀匹配

分析思路

  • 考点:数据库索引原理(B-tree 索引特性)、模糊查询优化、业务场景下的存储设计优化、索引失效场景。
  • 注意:需在应用层处理反转逻辑,避免每次查询计算REVERSE消耗CPU。
  • 代码示例
ALTER TABLE users 
ADD COLUMN name_reverse VARCHAR(64) 
GENERATED ALWAYS AS (REVERSE(name)) STORED, -- 或 VIRTUAL(消耗cpu不占磁盘)
ADD INDEX idx_name_reverse (name_reverse);

-- 查询:姓名以"晓明"结尾
SELECT * FROM users WHERE name like CONCAT('晓明', '%') or name_reverse LIKE CONCAT('明晓', '%');
-- 查询:姓名以"刘晓"开头
SELECT * FROM users WHERE name like CONCAT('刘晓', '%') or name_reverse LIKE CONCAT('晓刘', '%');

// 1. ES映射(Mapping)设计
PUT /users
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "keyword": { // 精确匹配字段
            "type": "keyword"
          },
          "reverse": { // 反向存储字段,用于后缀匹配
            "type": "keyword"
          }
        }
      }
    }
  }
}

// 2. 插入数据时同步反向姓名
PUT /users/_doc/1
{
  "name": "刘晓明",
  "name.keyword": "刘晓明",
  "name.reverse": "明晓刘"
}

// 3. 前缀匹配(以"刘晓"开头)
GET /users/_search
{
  "query": {
    "prefix": {
      "name.keyword": "刘晓"
    }
  }
}

// 4. 后缀匹配(以"晓明"结尾)
GET /users/_search
{
  "query": {
    "prefix": {
      "name.reverse": "明晓"
    }
  }
}

问答4:Spring AOP 什么时候会失效

面试官: 你用过Spring AOP吧?在什么情况下AOP会失效?能举个具体例子吗?

面试者: Spring AOP失效主要有6类场景:

  1. 内部方法调用this.method()指向原始目标对象而非代理对象,AOP不生效。可以改用ApplicationContext.getBean()AopContext.currentProxy()获取代理对象调用。
  2. 静态或final方法:AOP只能代理非静态方法,final方法不能被重写,无法代理。
  3. 私有方法:私有方法无法被子类继承,Spring框架规范不允许。
  4. 未被Spring管理的Bean:AOP仅对Spring容器中的Bean生效。
  5. 代理模式配置不当:未正确配置@EnableAspectJAutoProxy或代理方式。
  6. 在@PostConstruct注解方法中调用:调用带切面方法不会生效,因为 AOP代理对象还没有生成。

分析思路

  • 考点:Spring AOP 底层实现(JDK 动态代理 / CGLIB 代理)、代理对象调用机制、Spring Bean 生命周期
  • 注意:解决内部调用失效时,避免在 Bean 内部直接注入自身(可能导致循环依赖)
  • 代码示例
// 场景1:内部调用导致AOP失效(核心高频场景)
@Service
public class UserService {
    // 错误写法:this调用绕过代理,@CacheEvict不生效
    public void updateUser(Long userId) {
        this.clearUserCache(userId); // AOP失效
        // 业务逻辑:更新用户信息
    }

    @CacheEvict(value = "userCache", key = "#userId")
    public void clearUserCache(Long userId) {
        // 清理缓存逻辑
    }
}

// 正确写法1:通过ApplicationContext获取代理对象
@Service
public class UserService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private UserService proxyUserService;

    @PostConstruct
    public void init() {
        // 获取代理对象
        proxyUserService = applicationContext.getBean(UserService.class);
    }

    public void updateUser(Long userId) {
        // 用代理对象调用,AOP生效
        proxyUserService.clearUserCache(userId);
        // 业务逻辑
    }

    @CacheEvict(value = "userCache", key = "#userId")
    public void clearUserCache(Long userId) {
        // 清理缓存逻辑
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

// 正确写法2:使用AopContext(需配置@EnableAspectJAutoProxy(exposeProxy = true))
@Service
public class UserService {
    public void updateUser(Long userId) {
        // 获取当前代理对象
        UserService proxy = (UserService) AopContext.currentProxy();
        proxy.clearUserCache(userId); // AOP生效
        // 业务逻辑
    }

    @CacheEvict(value = "userCache", key = "#userId")
    public void clearUserCache(Long userId) {
        // 清理缓存逻辑
    }
}

// 场景2:final方法导致AOP失效(CGLIB无法代理)
@Service
public class OrderService {
    // final方法,AOP无法拦截
    @Transactional
    public final void createOrder() {
        // 下单逻辑
    }
}

// 场景3:未被Spring管理的Bean导致AOP失效
// 错误:new创建的对象,非Spring容器管理,AOP不生效
public class Test {
    public void test() {
        UserService userService = new UserService();
        userService.updateUser(1L); // AOP失效
    }
}

问答5:Spring事务理解

面试官:说一说你对Spring事务的理解和使用?
面试者:Spring事务本质是Spring框架对数据库事务的标准化封装与抽象,核心价值一是解耦——把事务开启、提交、回滚等底层操作和业务代码分离,不用手动操作JDBC的Connection;二是适配——通过PlatformTransactionManager统一抽象层,屏蔽不同数据源的事务实现差异,降低多数据源适配成本。

  • 执行机制:基于AOP动态代理实现声明式事务,接口类用JDK代理、非接口类用CGLIB代理,代理对象会在@Transactional方法执行前开启事务(setAutoCommit(false)),正常执行则提交,抛异常则回滚;
  • 关键配置:常用的传播行为:默认 REQUIRED(能合则合,不能合则创) 保证核心业务原子性,REQUIRES_NEW 用于核心与非核心操作隔离,NESTED 用于需要部分回滚的嵌套事务场景;很少用:SUPPORTS 适配查询类方法兼容有/无事务场景,MANDATORY 强制要求依赖父事务,NOT_SUPPORTED 强制非事务执行,NEVER 禁止在事务环境中执行。隔离级别生产优先选 READ_COMMITTED 平衡并发与一致性;必须配置 rollbackFor = Exception.class 覆盖全异常场景的回滚;readOnly=true 可优化纯查询事务的性能;;
  • 工程落地:重点解决事务失效问题——内部this调用绕代理(用AopContext/自注入代理解决)、非public方法失效(强制public)、多数据源需绑定专属事务管理器;同时通过缩短事务生命周期、拆分大事务优化高并发场景性能。
  • 详细介绍

1、REQUIRED 有则直接加入,无则新建。异常传染:如果内部方法不指定rollbackFor(默认),当抛出 RuntimeExceptionError异常没有捕获(AOP会标记rollback-only为true),外层方法把内层方法给捕获了,外层在提交事务会则会报 UnexpectedRollbackException失败;如果内部抛出IOExceptionSQLExceptionParseException等检查型异常没有捕获(AOP不会标记rollback-only为true),外层方法把内层方法给捕获了,注意此时外层事务是可以正常提交。假如内层方法自己捕获了没有抛出,但是外层事务自身抛出异常,则内层事务会一起会滚。简单一句话:不管是内层还是外层抛异常,只要触发回滚规则(异常类型要对、异常要抛出来、没有被noRollbackFor排除)就会全部回滚。适用90%的业务场景:如:订单创建 -> 扣减库存;

2、REQUIRES_NEW 如果当前有事务,强制挂起当前事务,创建一个全新的独立事务,如果当前没有事务,直接新建一个独立事务。执行完毕后,再恢复外层事务。异常传染:内部事务回滚,绝不影响外层事务(除非外层显式捕获异常并决定自己回滚),反之,外层回滚,也绝不影响已经提交的内部事务。适用业务场景:如审计日志/操作记录/发送通知;

3、NESTED 如果当前有事务,则在当前事务中创建一个保存点(Savepoint),如果没有,则行为同REQUIRED。异常传染:内层失败可以回滚到Savepoint,只撤销内层操作,外层可以继续执行或选择提交(注意:内层异常需要被外层捕获,不能继续往外抛,否则外层也会触发回滚),但是外层失败必然导致内层一起回滚。适用业务场景:复杂表单提交/批量处理中的部分回滚;

4、SUPPORTS有事务就加入,没事务就以非事务方式执行。业务场景:纯查询且对一致性要求不高的场景(如缓存预热/非核心配置/日志补充/通用查询工具等的查询);

5、NOT_SUPPORTED 如果有事务,强制挂起,以非事务方式执行。业务场景:执行耗时极长且不需要原子性的操作(如超大Excel报表);

6、MANDATORY 必须在现有事务中运行,否则直接抛异常 IllegalTransactionStateException。业务场景:用于代码契约检查,防止数据不一致(假如库存操作必须依赖创建订单、退单等,使用MANDATORY则可以避免库存操作服务被当成独立服务进行直接调用);

7、NEVER 必须在非事务环境下运行,如果有事务,抛异常。业务场景:用于明确知道不能在事务中执行的操作,防止被外层大事务意外包裹。

分析思路

  • 考点:1、理解Spring事务“抽象解耦”的核心价值,而非仅停留在API使用;2、掌握代理执行机制与核心参数的选型逻辑;3、能落地事务失效治理与性能优化。
  • 注意:1、应答要结合选型逻辑(如选 READ_COMMITTED 的原因),而非仅罗列配置;2、关联 AOP 代理解释事务失效情况,体现知识体系连贯性;3、突出实战经验,比如大事务拆分、异常需被 Spring 感知等核心落地要点。
  • 代码示例
@Service
public class OrderService {
    @Transactional(transactionManager = "masterTxManager", rollbackFor = Exception.class)
    public Long createOrder(OrderDTO dto) {
        Long orderId = orderMapper.insert(dto);
        // 非数据库操作移出事务,缩短锁持有时间
        CompletableFuture.runAsync(() -> mqProducer.sendMsg(orderId));
        return orderId;
    }
}

问答6:Spring事务隔离级别

面试官: 重点说说你对Spring事务隔离级别的理解?

面试者: Spring 事务隔离级别,本质是 Spring 对数据库事务隔离级别的标准化封装与传递,核心是控制并发事务间的数据可见性与一致性边界,最终的隔离逻辑是数据库实现的,Spring 只负责在开启事务时,把配置的隔离级别传递给数据库连接。

  • READ_UNCOMMITTED(读未提交):“裸奔模式”。能读到别人没提交的数据(脏读)。除了做实时大屏统计这种允许数据不准的场景,生产环境严禁使用。
  • READ_COMMITTED(读已提交,RC):“互联网高并发首选”(Oracle 默认)。解决了脏读,但防不住“不可重复读”(同一条数据前后读不一样)。优点是并发高,锁竞争少;缺点是业务逻辑要自己处理数据不一致(比如版本号校验)。
  • REPEATABLE_READ(可重复读,RR):“金融/库存级标配”(MySQL 默认)。解决了脏读和不可重复读。重点:MySQL 通过 MVCC+ 间隙锁(Gap Lock),实际上也基本解决了幻读。代价是范围查询会锁住间隙,容易死锁,并发略低于 RC。
  • SERIALIZABLE(串行化):“性能杀手”。强制事务排队执行,彻底解决所有问题,但并发能力几乎归零。除非系统要挂了保数据,否则别用,需要用业务队列代替。
  • DEFAULT(默认):“随波逐流”。完全看数据库脸色(MySQL 变 RR,Oracle 变 RC)。大忌:迁移数据库时行为会变,建议显式指定级别,不要依赖默认。

分析思路

  • 考点:1、三大并发问题(脏读、不可重复读、幻读)的本质区别;2、MySQL InnoDB 底层机制(MVCC 快照读 vs 间隙锁当前读)如何解决幻读;3、场景权衡(一致性 vs 吞吐量)。
  • 注意:1、幻读的真相:标准 RR 有幻读,但 MySQL RR 在“当前读”下通过 Next-Key Lock 堵住了幻读,仅在“先快照读后当前读”的特殊时序下有坑;2、根据生产环境的数据库默认级别或业务需求显式声明隔离级别,避免使用 Isolation.DEFAULT 导致跨库迁移时隔离级别不一致(比如从 MySQL 迁到 Oracle,默认级别会从 RR 变成 RC);3、死锁根源:RR 级别下的范围更新最容易因间隙锁导致死锁,优化方向是走主键精确查询。4、隔离级别要和传播行为配合使用,REQUIRES_NEW 的内层事务隔离级别独立,不会继承外层;同一个 RR 级别的事务内,混用快照读和当前读(SELECT ... FOR UPDATE),容易出现数据逻辑不一致,要尽量避免。
  • 代码示例
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private StockMapper stockMapper;

    // 生产级配置:指定读已提交隔离级别,平衡并发与一致性,全异常回滚
    @Transactional(
            isolation = Isolation.READ_COMMITTED,
            rollbackFor = Exception.class,
            transactionManager = "masterTxManager"
    )
    public Long createOrder(OrderDTO dto) {
        // 精准查询,避免RR级别下的大范围间隙锁
        Stock stock = stockMapper.selectByProductIdForUpdate(dto.getProductId());
        if (stock.getStockNum() < dto.getCount()) {
            throw new RuntimeException("库存不足");
        }
        // 扣库存、创建订单
        stockMapper.decreaseStock(dto.getProductId(), dto.getCount());
        Long orderId = orderMapper.insert(dto);
        return orderId;
    }
}

问答7:Zookeeper的选举机制

面试官: ZooKeeper的Leader选举机制是怎样的?为什么需要选举?能结合实际场景说明吗?

面试者: ZooKeeper选举基于Zab协议(ZooKeeper Atomic Broadcast),采用Fast Leader Election算法。核心逻辑是:

  1. 触发条件:集群启动或Leader宕机后(如网络分区)。
  2. 选举流程
    • 每个节点广播myid(节点ID)、epoch(逻辑时钟)、zxid(事务ID)。
    • 节点投票给zxid最大的节点;若zxid相同,投票给myid最大的节点。
    • 当节点收到过半(N/2+1) 选票时,成为Leader。
  3. 关键设计
    • 过半机制:3节点集群需2票(避免脑裂),5节点需3票。
    • epoch递增:每次选举epoch+1,确保新Leader的zxid更大。
    • Observer角色:不参与选举(如只读节点),提升吞吐量。

分析思路

  • 考点:Zab协议核心机制(选举条件、过半原则)、节点角色(Leader/Follower/Observer)。
  • 注意:避免配置tickTime过小(导致频繁选举),Observer不参与选举(需单独配置)。
  • 代码示例
# zoo.cfg
tickTime=2000  # 心跳间隔
initLimit=10   # 初始化连接超时
syncLimit=5    # Leader同步Follower超时
server.1=192.168.1.1:2888:3888
server.2=192.168.1.2:2888:3888
server.3=192.168.1.3:2888:3888

问答8:RocketMQ如何保证消息不丢失

面试官: 你用过RocketMQ吧,是如何做到保证消息不丢失的。

面试者: RocketMQ保证消息不丢失需要覆盖生产端→Broker端→消费端三个环节,具体方案是:

  1. 生产端(Producer→Broker)
    • 同步发送+重试:必须用send()同步发送(非oneway),校验SendStatus,失败重试。
    • 事务消息:核心业务用事务消息保证本地事务与消息一致性(如订单支付),通过executeLocalTransactioncheckLocalTransaction确保两阶段提交。
  2. Broker端(存储可靠性)
    • 同步刷盘broker.conf中配置flushDiskType=SYNC_FLUSH(非默认的异步刷盘),确保消息写入磁盘才返回ACK。
    • 主从同步复制brokerRole=SYNC_MASTER,主节点写入后等待从节点同步完成再返回确认,避免单点故障丢失数据。
  3. 消费端(Broker→Consumer)
    • 手动提交offset:消费成功后返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS,避免自动提交导致重复消费。
    • 消费重试机制:Broker默认重试16次,重试失败进入死信队列;消费端需实现幂等(如订单ID去重),避免重复处理。

分析思路

  • 考点:消息全链路可靠性设计(三个环节缺一不可),避免"以为用了MQ就绝对不丢"的误区。
  • 注意:同步刷盘会降低吞吐量,需权衡可靠性与性能;事务消息仅适用于核心业务,非必要不滥用。
  • 代码示例
// 同步发送失败重试
SendResult result = producer.send(msg);
if (result.getSendStatus() != SendStatus.SEND_OK) {
    // 重试或记录告警
}
producer.setRetryTimesWhenSendFailed(3); // 重试3次

// 消费重试
public ConsumeConcurrentlyStatus consume(MessageExt msg) {
    if (reconsumeTimes > 2) {
        // 重试3次失败,存入本地日志
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
    // 业务逻辑
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}

问答9:Kafka如何保证消息不丢失

面试官: 说一说Kafka是怎么保证消息不丢失?

面试者: Kafka要保证消息不丢失,必须覆盖生产端→Broker端→消费端三个环节,具体方案如下:

  1. 生产端(Producer)
    • acks=all:设置acks=-1(或acks=all),确保消息被所有ISR副本确认才返回成功。
    • 重试机制:配置retries=3retry.backoff.ms=300,网络波动时自动重试。
    • 幂等性:开启enable.idempotence=true(默认开启),避免重试导致重复消息。
  2. Broker端
    • 副本机制replication.factor=3min.insync.replicas=2,确保数据至少有2个副本同步。
    • 持久化策略:配置log.flush.interval.messageslog.flush.interval.ms,确保消息及时刷盘。
    • 避免脏选举unclean.leader.election.enable=false,防止非同步副本被选为Leader。
  3. 消费端(Consumer)
    • 手动提交offset:关闭自动提交enable.auto.commit=false,消费成功后调用commitSync()
    • 消费失败处理:失败消息写入死信队列(DLQ),避免阻塞正常消费。

分析思路

  • 考点:消息全链路可靠性设计(三个环节缺一不可),避免"以为Kafka默认不丢"的误区。
  • 注意acks=all会降低吞吐量,需权衡可靠性与性能;事务消息仅用于核心业务,非必要不滥用。
  • 代码示例
Properties props = new Properties();
props.put("acks", "-1");
props.put("retries", 3);
props.put("retry.backoff.ms", 300);


consumer.subscribe(Collections.singletonList("topic"));
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        process(record.value()); // 处理消息
        consumer.commitSync(); // 手动提交
    }
}

问答10:反问环节

面试官:好了,我的问题问完了,有什么问题想了解的吗?
面试者:非常感谢今天的面试,现在对公司和团队有了更多的了解。想请教两个问题:一是咱们团队目前在业务和系统上,主要面临哪些技术挑战或性能瓶颈?二是如果我入职,这个岗位短期内的核心职责与预期产出大概是怎样的?
分析思路

  • 考点:体现面试者关注业务痛点、技术攻坚与价值产出,符合能扛事、能解决问题的定位。
  • 注意:聚焦业务挑战、岗位职责与价值贡献,不问薪资、加班、福利等敏感问题,展现成熟、务实、有担当的专业形象。

【关注 Java 架构老羊 免费】持续更新 ✨ Java 后端、面试真题、技术架构、性能调优干货。
点赞收藏不迷路 📌,

本文为作者原创内容,未经授权,禁止任何形式的转载、抄袭、洗稿;如需引用,请注明原文出处。