卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • Java面经

    • 阿里面经
    • 11.23阿里面经
    • 26.4.21阿里Java后端开发
    • 26.4.21阿里Java实习
    • 12.4美团面经
    • 美团日常实习一面
    • 26.2.1美团Java日常实习
    • 26.2.2美团一二面
    • 26.2.5美团Java实习
    • 26.2.8美团一二面
    • 26.2.20美团Java后端实习
    • 26.2.22美团后端面经
    • 26.3.1美团Java后端技术
      • 12.27腾讯面经
      • 腾讯日常实习Java技术
      • 26.3.7腾讯Java秋招
      • 26.4.4腾讯天美后台开发
      • 腾讯云面经
      • 26.1.1字节跳动二面
      • 26.1.10字节跳动后端一面
      • 26.1.10字节跳动后端二面
      • 26.1.25字节电商后端
      • 26.4.3小红书Java面经
      • 26.4.12小红书后端一面
      • 26.4.13小红书研发一面
      • 26.4.28百度面经
      • 12.10京东面经
      • 26.1.22海康威视面经
      • 快手一面面经
      • 盒马面经
      • 众安后端一面面经

    # 美团 Java 后端技术面经

    # 为什么String不可变,StringBuilder可变?

    1. String是不可变的字符串类,因为其内部数组使用了final修饰,且数组本身是私有且不对外开放修改,因此每次改变String对象会创建新的String对象。由于String的不可变,String的线程是安全的,适合常量等字符串不经常变化的场景。
    2. StringBuilder基于char[] value实现的,数组可扩容,能够高效拼接字符串,还有append()、insert()方法可以直接修改数组内容,扩容时会创建新数组并复制数据,对象引用不变,但是StringBuilder线程不安全,适合单线程场景。

    # 介绍一下synchronized和Reentranlock?

    1. synchronized是基于JVM的内置隐式锁,线程在进入/退出代码是JVM会自动获取释放锁,且只能用于方法和代码块;ReentrantLock是Java提供的显式锁机制,是Lock接口的一个具体实现类,拥有Lock接口的特性,需要手动调用lock与unlock方法。二者都是可重入锁,同一个线程可以多次获取同一个锁。
    2. synchronized是非公平锁,且不支持响应中断;ReentrantLock可以进行公平性的设置,线程在等待锁时可以中断。
    3. synchronized不支持绑定多个条件,只能和wait()和notify()/notifyAll()方法一起使用,实现线程等待与通知;ReentrantLock可以与多个Condition对象结合,实现复杂的线程同步机制。
    4. ReentrantLock可以提供更细粒度的控制和灵活性,性能高于synchronized。

    # 使用上面两种锁,有什么注意事项?

    1. 使用synchronized时,不能让锁的粒度太大,如果给整个方法加锁会造成线程阻塞,仅锁定需要同步的代码块;同时不要使用String常量或者Integer等不可变的对象作为锁,否则会导致不同线程竞争同一把锁;如果是静态方法,锁的是类对象,实例方法的锁则是锁对象实例,两者不互斥。
    2. 使用ReentrantLock时注意需要手动释放锁,锁必须在finally中释放,否则出现异常时会导致锁无法释放而引发死锁;避免重复释放锁,多次调用unlock()会抛出异常;尽量不要使用公平锁,如果需要保证线程执行顺序时再开启,否则会为了维护等待队列降低性能;可以使用tryLock()避免线程永久阻塞,超时后会返回false,要处理未获取锁的场景;ReentrantLock允许线程在等待锁时被中断,所以要捕获InterruptedException并处理。

    # join方法有哪些类型?

    1. join()是Thread类中的一个方法,用于让一个线程等待另一个线程执行完成后再继续执行。主要有三种重载类型:join()、join(long millis)、join(long millis, int nanos)。

    2. join()是无参方法,会在底层调用wait()释放目标线程对象的内置锁,当线程调用thread.join()时,当前线程会进入WAITING状态,等待thread线程执行完毕后恢复;

      join(long millis)能够指定等待时长,若等待millis毫秒后目标线程仍未执行完,当前线程不再等待,继续执行,如果millis=0,则与join()无参方法一样,等待目标线程执行完毕。

      join(long millis, int nanos)能够有更精细的等待时长,底层会将纳秒向上取整为毫秒。

    # 怎么优化sql语句?

    1. 可以给查询条件、排序和分组的字段建立索引,但是不要使用select*语句和对索引字段进行函数/表达式运算避免索引失效,但是如果数据量比较小或者查询低频可以不使用索引,否则还需要维护索引影响开销。
    2. 还可以把子查询替换为JOIN,子查询可能导致全表扫描,JOIN的性能更好;把OR替换为IN和使用LIMIT限制返回行数也可以优化写法。

    # 怎么查看执行计划?

    • 在MySQL使用EXPLAIN和待优化的SQL可以查看执行计划,在MySQL8.0开始还可以使用EXPLAIN ANALYZE实际执行SQL并返回执行时间和扫描行数。

    # explain的重点属性有哪些?

    1. 关注type字段:反映查询数据的方式。ALL是全表扫描,效率最差,可能存在索引失效或没有索引的问题;

      index是全索引扫描,没有命中有效筛选;range是索引范围查询;

      ref是使用普通索引作为查询条件,可能会找到多个符合条件的行;

      eq_ref则是联表查询时被关联表的主键或唯一索引的字段作为条件,前一张表的行在当前表只有一行对应;

      system/const是主键或唯一索引匹配,最多返回一条记录,效率最高。

    2. 关注key字段,可以看到实际使用的索引,如果为NULL则未使用到。

    3. 关注Extra字段,可以看到MySQL执行查询额外信息。

      Using filesort是在排序时使用了外部的索引排序,没有用到表内索引进行排序。

      Using temporary是存在ORDER BY和GROUP BY的情况,需要创建临时表来存储查询的结果。

      Using index是使用了覆盖索引,不用回表;

      Using where表明查询时使用了WHERE进行过滤。需要尽可能避免出现Using temporary和Using filesort的情况。

    # 自动装配的原理是什么?

    1. SpringBoot的自动配置是基于条件的按需配置,本质是通过注解驱动+SPI机制,根据项目依赖、环境配置、自定义规则,自动向IoC容器注入对应Bean,替代传统Spring的XML手动配置。
    2. SpringBoot是通过@SpringBootApplication注解中的@EnableAutoConfiguration触发自动配置,借助SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类;通过条件注解(如@ ConditionalOnClass)筛选出符合当前环境的配置类后,向IoC容器注入默认Bean;同时遵循 “自定义优先” 原则,开发者可手动配置Bean或禁用自动配置类,覆盖默认行为,最终实现 “按需配置、简化开发” 的目标。

    # 自动装配过程是怎样的?

    1. 扫描阶段:Spring容器启动,会通过@ComponentScan指定扫描包,扫描所有标注@Component及其衍生注解的类,生成BeanDefinition,也就是bean的定义信息;
    2. 注册阶段:将BeanDefinition注册到BeanFactory中,此时仅保存bean的元信息,未创建实例;
    3. 实例化阶段:容器首次获取bean时,会通过反射根据BeanDefinition创建 bean 实例;
    4. 依赖解析阶段:AutowiredAnnotationBeanPostProcessor扫描bean的字段、setter方法、构造方法上的@Autowired注解,解析需要注入的依赖类型 / 名称;
    5. 依赖查找阶段:根据解析的依赖信息,从BeanFactory中查找匹配的bean:优先按类型查找;若找到多个同类型 bean,按名称匹配(byName);若仍匹配失败,抛出NoUniqueBeanDefinitionException(可通过@Qualifier指定bean名称解决);
    6. 注入阶段:将找到的依赖bean注入到当前bean的字段 / 方法中,完成自动装配;
    7. 初始化阶段:调用@PostConstruct注解的方法,完成bean的初始化。

    # 设计模式应用场景有哪些?

    1. 单例模式用于保证全局唯一的对象(如配置类、连接池、日志工厂、Spring 的 Bean 默认单例),可以分为两类实现方式,其中饿汉式在启动时创建,线程安全、懒汉使用双重检查锁,可以进行延迟加载。 image
    2. 工厂模式有三种类型,简单工厂创建同一类别的对象(如不同类型的日志记录器:FileLogger、ConsoleLogger);工厂方法是每个产品对应一个工厂(如 Spring 的BeanFactory,不同子类创建不同 bean);抽象工厂则负责创建一组相关对象(如跨平台 UI 组件:WindowsButton + WindowsText / LinuxButton + LinuxText)。 image image
    3. 代理模式可以增强对象功能(如Spring AOP、事务管理、日志记录、权限控制);典型实现拥有静态代理(手动编写代理类)、动态代理(JDK 动态代理、CGLIB)。 image
    4. 适配器模式用于兼容不同接口(如 SpringMVC 的HandlerAdapter,适配不同的 Controller 处理器;Java 的InputStreamReader将字节流适配为字符流)。
    5. 装饰器模式用于动态增强对象功能(如 Java IO 的BufferedReader装饰FileReader,增加缓冲功能;Spring 的DataSource装饰器,增加连接池功能)。
    6. 观察者模式是一对多的通知机制(如 Spring 的事件监听机制、Guava 的 EventBus、消息队列的发布订阅)。 image
    7. 策略模式用于进行多种算法/规则的动态切换(如支付方式选择:AlipayStrategy、WechatPayStrategy;排序算法选择:QuickSortStrategy、BubbleSortStrategy)。 image

    # 介绍一下Java的异常?

    1. Java的异常体系以Throwable为根类,有Error和Exception两个子类;

    2. Error表示运行时环境的错误,是程序无法处理的问题,可能是系统崩溃,虚拟机错误等。

    3. Exception是程序本身可以处理的异常,分为非运行时异常和运行时异常。

      非运行时异常在编译时就必须被捕获或声明抛出,比如文件不存在(FileNotFoundException)、类未找到(ClassNotFoundException)等,程序员必须进行显式抛出;

      运行时异常则是由代码逻辑错误导致的,比如数组越界、空指针异常等。一般可以通过try...catch...finally捕获异常或使用throw/throws抛出异常。

    # 你在项目中是怎么打印日志的?

    1. 一般来说,我会使用SLF4J+Logback日志框架统一日志,按照ERROR、WARN、INFO和DEBUG四个级别进行分类打印,ERROR是系统异常、业务错误、必须打堆栈;WARN则是打印参数不合法、调用超时、可恢复异常;INFO是接口入参出参等核心流程节点信息;DEBUG是本地调试的时候使用。
    2. 我在日志中会打印时间、线程名、类名、方法名、请求ID、业务ID和描述信息等内容。通常在项目的关键位置设置日志打印,如接口入参出参、核心业务逻辑、异常catch块与第三方接口相关的操作处设置。

    # 开发项目时遇到性能瓶颈怎么解决?

    1. 我在开发过程中遇到瓶颈会先尝试定位问题,比如观察接口的响应时间、链路耗时是否合理,是否出现了MySQL的慢查询、Redis的命中率过低等问题;然后判断瓶颈问题属于代码、数据库、中间件还是系统架构问题;
    2. 如果是SQL相关,可以尝试添加索引避免全表扫描或者分页优化,减少代码中的循环,还可以补充添加缓存内容,将不做同步要求的业务改为异步,进行池化。在架构方面可以采用读写分离、多级缓存和异步解耦以解决。
    Last Updated: 4/30/2026, 11:54:17 AM

    ← 26.2.22美团后端面经 12.27腾讯面经 →

    评论

    验证登录状态...

    侧边栏
    夜间
    卡码简历
    代码随想录
    卡码投递表🔥
    2026群
    添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
    支持卡码笔记
    鼓励/支持/赞赏Carl
    1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
    2. 希望大家都能梦想成真,有好的前程,加油💪