目录

谭同学的面经(2025-8)

目录

百度C++(搜索架构部/2025-08-11)

讲一下你工作中独立负责的项目或者比较大的开发工作

怎么会想到使用图技术?怎么做的技术选型

并发?怎么解决并发问题?

在项目中有没有遇到过性能优化问题?C++ 有内存泄露,内存雪花

对C++ ,介绍一下内存呢管理

算法

K和升序集合,求交集

// 测试用例数组 vector<vector> arrays1 = { {1, 3, 5, 7, 9}, {2, 3, 5, 8, 9}, {3, 5, 6, 9, 10} };

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <vector>
#include <climits>  // 用于 INT_MAX

using namespace std;

// 函数声明(也可直接把函数定义写在 main 之前,这里演示标准写法)
vector<int> intersect(const vector<vector<int>>& arrays);

int main() {
    // 测试用例数组
    vector<vector<int>> arrays1 = {
        {1, 3, 5, 7, 9},
        {2, 3, 5, 8, 9},
        {3, 5, 6, 9, 10}
    };

    // 调用求交集函数
    vector<int> result = intersect(arrays1);

    // 输出结果
    cout << "交集结果: ";
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

// 函数定义:K 个升序数组求交集
vector<int> intersect(const vector<vector<int>>& arrays) {
    vector<int> res;
    if (arrays.empty()) {
        return res;
    }

    // 记录每个子数组当前遍历的指针位置  子数组的指针
    // 创建一个与 arrays 大小相同的 vector 容器,所有元素都初始化为 0
    vector<int> pointers(arrays.size(), 0);
    while (true) {
        int min_val = INT_MAX;
        bool all_same = true;

        // 1. 找到当前所有指针位置的最小值,同时检查是否越界
        for (size_t i = 0; i < arrays.size(); ++i) {
            if (pointers[i] >= arrays[i].size()) {
                // 某个数组已遍历完,直接返回结果
                return res;
            }
            if (arrays[i][pointers[i]] < min_val) {
                min_val = arrays[i][pointers[i]];
            }
        }

        // 2. 检查所有指针位置的值是否都等于最小值
        for (size_t i = 0; i < arrays.size(); ++i) {
            if (arrays[i][pointers[i]] != min_val) {
                all_same = false;
                break;
            }
        }

        // 3. 处理逻辑:相等则加入结果,所有指针后移;否则只移动对应指针
        if (all_same) {
            res.push_back(min_val);
            for (size_t i = 0; i < arrays.size(); ++i) {
                pointers[i]++;
            }
        } else {
            for (size_t i = 0; i < arrays.size(); ++i) {
                if (arrays[i][pointers[i]] == min_val) {
                    pointers[i]++;
                }
            }
        }
    }
}

手动实现一下memcpy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstddef>  // 用于 size_t 类型
#include <iostream>
using namespace std;

// 手动实现 memcpy,模拟标准库行为
// dest: 目标内存起始地址
// src:  源内存起始地址
// count: 要拷贝的字节数
void* my_memcpy(void* dest, const void* src, size_t count) {
    // 1. 空指针保护(可选,标准库 memcpy 不检查,传递空指针会崩溃)
    if (dest == nullptr || src == nullptr) {
        return nullptr;
    }

    // 2. 转换为 unsigned char* 操作单个字节
    // unsigned char 能正确表示所有可能的字节值,不会有符号扩展问题
    unsigned char* dest_ptr = static_cast<unsigned char*>(dest);
    const unsigned char* src_ptr = static_cast<const unsigned char*>(src);

    // 3. 逐字节拷贝
    for (size_t i = 0; i < count; ++i) {
        dest_ptr[i] = src_ptr[i];
    }

    // 4. 返回目标地址(符合标准库 memcpy 返回值)
    return dest;
}

// 测试用例
int main() {
    // 源数据
    char src[] = "Hello, Manual memcpy!";
    // 目标缓冲区
    char dest[100] = {0}; 

    // 调用自定义 memcpy
    my_memcpy(dest, src, sizeof(src));  

    // 输出结果
    cout << "源数据: " << src << endl;
    cout << "目标数据: " << dest << endl;

    return 0;
}

百度C++二面(搜索架构部/2025-08-13)

讲一下简历里面的项目是怎么设计的?【主要聊简历项目: 设计、数据层、服务层、应用层】

讲一下内存泄漏问题, C++为例

写一个生产者,消费者模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumerDemo {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 5;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public static void main(String[] args) {
        ProducerConsumerDemo pc = new ProducerConsumerDemo();
        new Thread(pc::produce, "Producer").start();
        new Thread(pc::consume, "Consumer").start();
    }

    public void produce() {
        int value = 0;
        while (true) {
            lock.lock();
            try {
                while (queue.size() == capacity) {
                    notFull.await();
                }
                System.out.println("Produced: " + value);
                queue.add(value++);
                notEmpty.signal();
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public void consume() {
        while (true) {
            lock.lock();
            try {
                while (queue.isEmpty()) {
                    notEmpty.await();
                }
                int value = queue.poll();
                System.out.println("Consumed: " + value);
                notFull.signal();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

华盛通一面-港美股券商(2025-08-28)

计算机网络分层模型?

TCP和UDP的区别是怎样的?大部分是用TCP还是UDP?

在工作中有用到网络编程吗?

HTTP状态码:100, 200, 300, 400, 500系列什么意思?

306?307?

知道http请求header中的keep-alive什么含义?

在TCP中怎么区分每个request和response的边界?

content-length

transfer-coding: chunked

Spring: @Controller和@RestController有什么区别?

HashMap的底层数据结构是怎样的? 将一下一个key去找value的过程?

一个对象没有重写equals和hashcode方法,把这个对象作为hashmap的key会不会出现异常情况?

equals hashcode

在java规范中,如果equals相等,那么hashcode一定相等吗?

服务器CPU使用率飙升,如何定位?正常的处理流程?

熟悉哪些微服务调度框架?讲一个?doubble? springcloud?

闭源技术?遇到问题如何处理?

MySQL:如何处理慢查询?

华盛通二面-港美股券商(2025-09-01)

项目中有用到微服务吗?介绍一下

一个程序的前端请求到了后端,请求是怎么流转的

对象序列化知道吗?dubble的序列化框架是啥?

怎么评价一个序列化好与不好?量化维度

如何让线程暂停? Object.wait()怎么使用?

阻塞队列什么时候会阻塞?

易大宗 2025-12-08

java中int和Integer的区别?

数据类型

  • int是Java的基本数据类型,用于表示整数值,占用固定的内存空间。
  • Integer是Java的包装类,用于将int类型的数据包装成对象,从而可以作为类的实例来使用。

装箱和拆箱

  • int是基本数据类型,不是对象,不能直接参与面向对象的操作,需要通过装箱(boxing)将int类型转换成Integer对象。
  • Integer对象通过拆箱(unboxing)转换成int类型。

可空性

  • int是基本数据类型,不能表示为null,即int类型的变量总是有初始值的。
  • Integer是一个类,是引用类型,可以表示为null,即Integer类型的变量可以赋值为null,表示不存在数值。

内存占用

  • int类型的变量占用的内存空间固定,通常是4个字节(32位)。
  • Integer类型的对象占用的内存空间较大,除了保存值以外,还需要额外的空间用于对象头和其他元数据。

性能

  • int是基本数据类型,在计算和比较等操作时性能较好,因为不涉及装箱和拆箱的开销。
  • Integer是引用类型,涉及装箱和拆箱的开销,性能相对较差,尤其在大量数据操作时会有一定的性能损耗。

初始化默认值

  • int类型的变量在声明时会自动初始化为0。
  • Integer类型的对象在声明时如果没有初始化,会默认为null。

适用场景

  • int适用于需要简单的整数运算和存储的场景,例如计数器、数组索引等。
  • Integer适用于需要在对象中使用整数值,或者需要表示可能为null的整数值的场景,例如集合类、泛型等。

参与运算方式

  • int类型的变量可以直接参与数值运算。
  • Integer类型的对象需要先进行拆箱为int,然后才能进行数值运算。

String StringBuffer StingBuilder的区别?

特性 String StringBuffer StringBuilder
可变性 不可变(final) 可变 可变
线程安全 线程安全(不可变) 线程安全(同步方法) 非线程安全
性能 最差(每次操作生成新对象) 中等(同步开销) 最优(无同步开销)
存储位置 常量池(JVM内部优化) 堆内存 堆内存
适用场景 静态字符串、少操作 多线程环境,频繁篡改 单线程环境、频繁篡改

关键区别解析

可变性‌

  • String 是不可变的,任何修改操作都会生成新对象。
  • StringBuffer 和 StringBuilder 是可变的,通过 append() 方法直接修改原对象。

线程安全‌

  • String 由于不可变性天然线程安全。
  • StringBuffer 通过 synchronized 保证线程安全。
  • StringBuilder 无同步机制,线程不安全但性能最优。

性能‌

  • String 拼接时频繁创建新对象,性能最差。
  • StringBuffer 同步开销导致性能中等。
  • StringBuilder 无同步开销,性能最优。

存储位置‌

  • String 存储在常量池,JVM 优化内存使用。
  • StringBuffer 和 StringBuilder 存储在堆内存。

适用场景建议 静态字符串‌:使用 String。 多线程环境‌:使用 StringBuffer。 单线程大数据量操作‌:使用 StringBuilder。

总结‌:选择时优先考虑线程安全需求和操作频率,StringBuilder 在单线程场景下性能最优。

介绍一下ThreadLocal

一、核心概念

ThreadLocal‌ 是 Java 提供的线程局部变量类,用于为每个线程创建独立的变量副本,避免多线程环境下的共享变量冲突。其核心机制是通过 Thread 类的 ThreadLocalMap 存储变量副本,每个线程对副本的修改互不影响。

二、工作原理

  1. 存储结构
    • 每个线程内部维护一个 ThreadLocalMap,以 ThreadLocal 实例为键、变量副本为值的映射表。
    • ThreadLocalMap 采用弱引用存储 ThreadLocal 键,避免内存泄漏。
  2. 核心方法
    • set(T value):将值存入当前线程的 ThreadLocalMap
    • get():从当前线程的 ThreadLocalMap 获取值。
    • remove():删除当前线程的 ThreadLocalMap 中的值。
  3. 生命周期
    • 变量在当前线程存活期间有效,线程结束时自动回收。

三、典型应用场景

  1. 线程上下文传递
    • 在跨线程调用中传递请求上下文(如用户信息、请求ID)。
    • 示例:Spring MVC 中通过 RequestContextHolder 获取请求信息。
  2. 数据库连接管理
    • 每个线程独立管理数据库连接(如 MyBatis 的 SqlSession)。
    • 避免线程间连接冲突。
  3. 事务管理
    • 手动管理事务上下文,保证事务隔离性。
    • 示例:Spring 事务管理器通过 ThreadLocal 存储事务状态。

四、注意事项

  • 内存泄漏风险‌:若 ThreadLocal 键未被及时移除,可能导致 ThreadLocalMap 持有线程引用,引发内存泄漏。
  • 线程隔离性‌:ThreadLocal 仅在当前线程内有效,子线程无法继承父线程的 ThreadLocal 值(需使用 InheritableThreadLocal)。
  • 性能影响‌:频繁创建和销毁 ThreadLocal 可能导致性能开销,建议在类级别静态声明。

五、实现优势

  • 避免同步锁‌:通过副本隔离,消除线程间竞争,提升并发性能。
  • 简化代码‌:替代参数传递,减少方法签名复杂度。
  • 线程安全‌:每个线程独立操作变量副本,无需额外同步措施。

Spring中Bean的生命周期?

Spring 中 Bean 的生命周期详解

Spring Bean 的生命周期包括从创建到销毁的整个过程,主要分为以下五个阶段:

实例化(Instantiation)‌

描述‌:为 Bean 分配内存空间,通过构造函数或工厂方法创建实例。 时机‌:单例 Bean 在容器启动时实例化;原型 Bean 在每次获取时实例化。 关键点‌:仅分配内存,未进行属性赋值和依赖注入。

属性赋值(Property Population)‌

描述‌:将配置的属性值注入到 Bean 的属性中。 时机‌:实例化后立即执行。 关键点‌:通过 setXxx() 方法设置属性值。

初始化(Initialization)‌

描述‌:执行 Bean 的初始化逻辑,包括以下步骤: Aware 接口回调‌:如 setBeanName()、setBeanFactory()、setApplicationContext()。 BeanPostProcessor 前置处理‌:postProcessBeforeInitialization()。 初始化方法‌:通过 @PostConstruct 注解、InitializingBean 接口或 XML 配置的 init-method。 BeanPostProcessor 后置处理‌:postProcessAfterInitialization()。 时机‌:属性赋值后立即执行。 关键点‌:将 Bean 转换为可使用的状态。

使用(Usage)‌

描述‌:Bean 在应用程序中被调用和使用。 时机‌:初始化后立即开始。 关键点‌:Bean 的核心业务逻辑执行阶段。

销毁(Destruction)‌

描述‌:执行 Bean 的销毁逻辑,包括以下步骤: 销毁方法‌:通过 @PreDestroy 注解、DisposableBean 接口或 XML 配置的 destroy-method。 时机‌:单例 Bean 在容器关闭时销毁;原型 Bean 由垃圾回收机制处理。 关键点‌:释放资源、关闭连接等清理操作。

关键扩展点

  • 生命周期钩子‌: 初始化方法‌:@PostConstruct、init-method、InitializingBean。 销毁方法‌:@PreDestroy、destroy-method、DisposableBean。

  • BeanPostProcessor‌: 作用‌:在 Bean 初始化前后执行自定义逻辑。 方法‌:postProcessBeforeInitialization()、postProcessAfterInitialization()。

  • 单例 vs 原型‌: 单例‌:容器启动时实例化,容器关闭时销毁。 原型‌:每次获取时实例化,由垃圾回收机制销毁。

    示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class MyBean implements InitializingBean, DisposableBean {
    @PostConstruct
    public void init() {
        System.out.println("Bean 初始化");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Bean 销毁");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean 初始化");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean 销毁");
    }
}

注意‌:实例化和初始化是两个独立阶段,实例化仅分配内存,初始化涉及属性赋值和业务逻辑执行。

Spring的事务隔离级别?

Spring的事务隔离级别主要基于数据库的隔离级别实现,分为5种标准级别(对应SQL标准):

  1. ‌**默认隔离级别(Isolation.DEFAULT)**‌ 使用数据库的默认隔离级别,如MySQL的可重复读(REPEATABLE_READ),Oracle的读已提交(READ_COMMITTED)。
  2. ‌**读未提交(Isolation.READ_UNCOMMITTED)**‌ 允许读取未提交的数据,可能导致脏读、不可重复读和幻读问题。
  3. ‌**读已提交(Isolation.READ_COMMITTED)**‌ 避免脏读,但可能仍出现不可重复读和幻读。
  4. ‌**可重复读(Isolation.REPEATABLE_READ)**‌ 避免脏读和不可重复读,但可能仍出现幻读(如InnoDB通过多版本并发控制实现)。
  5. ‌**串行化(Isolation.SERIALIZABLE)**‌ 最高隔离级别,完全避免脏读、不可重复读和幻读,但性能最低(通过表级锁实现)。

Maven 遇到Jar包冲突怎么解决?

在 Maven 项目中遇到 Jar 包冲突时,可采用以下几种高效解决方法:

  1. ‌基础排除法( 标签)‌ 适用场景‌:排除直接依赖中的传递性冲突包。 操作示例‌:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
 <exclusion>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
 </exclusion>
  </exclusions>
</dependency>

要点‌:无需指定被排除依赖的版本,仅作用于当前声明的依赖项。 2. ‌多层级依赖排除‌ 适用场景‌:冲突由间接依赖(非直接引入)引起。 操作示例‌:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
  <groupId>com.example</groupId>
  <artifactId>module-a</artifactId>
  <exclusions>
 <exclusion>
   <groupId>org.hsqldb</groupId>
   <artifactId>hsqldb</artifactId>
 </exclusion>
  </exclusions>
</dependency>

原理‌:依赖树 A→ B → hsqldb,在 A 的依赖声明中排除 hsqldb 即可切断传递链。 3. ‌全局依赖管理(dependencyManagement)‌ 适用场景‌:统一管理多模块项目的依赖版本。 操作示例‌:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- 父 POM -->
<dependencyManagement>
  <dependencies>
 <dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-core</artifactId>
   <version>2.17.1</version> <!-- 安全版本 -->
 </dependency>
  </dependencies>
</dependencyManagement>

作用‌:强制所有子模块使用统一版本。 4. ‌重定位类(maven-shade-plugin)‌ 适用场景‌:解决第三方依赖之间的冲突。 操作示例‌:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
 <execution>
   <phase>package</phase>
   <goals>
     <goal>shade</goal>
   </goals>
   <configuration>
     <relocations>
       <relocation>
         <pattern>com.google.common</pattern>
         <shadedPattern>com.shaded.google.common</shadedPattern>
       </relocation>
     </relocations>
   </configuration>
 </execution>
  </executions>
</plugin>

效果‌:将依赖的第三方 jar 包重命名后打包到项目 jar 包中。 5. ‌类隔离策略‌ 适用场景‌:解决运行时类冲突。 技术示例‌:Flink、SOFAArk、Tomcat 等框架通过类加载策略实现隔离。 6. ‌依赖树分析‌ 操作步骤‌:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mvn dependency:tree  # 查看完整依赖树
mvn dependency:tree -Dincludes=冲突包名  # 精准定位冲突包

工具辅助‌:IDEA 安装 Maven Helper 插件可直观查看冲突情况。
7. ‌版本规则优先级‌
原则‌:
最短路径优先‌:路径更短的依赖版本生效。
先声明优先‌:路径长度相同时,先声明的依赖版本生效。
注意事项
运行时冲突‌:编译时解决方法可能引发运行时类找不到问题,需结合类隔离策略。
第三方冲突‌:重定位类和类隔离策略更适用于第三方依赖冲突。

通过以上方法,可有效解决 Maven 项目中的 Jar 包冲突问题。

### Mybatis中如何避免SQL注入?

1. **使用MyBatis的参数绑定**

MyBatis提供了预处理语句(PreparedStatement)的支持,这是避免SQL注入的关键。在MyBatis中,你应该使用`#{}`来绑定参数,而不是使用`${}`。`#{}`会自动地使用PreparedStatement的参数绑定,而`${}`会将参数直接嵌入到SQL语句中,这可能导致SQL注入。

```xml
<select id="selectUsers" resultType="User">
  SELECT * FROM users WHERE username = #{username}
</select>

错误使用

1
2
3
<select id="selectUsers" resultType="User">
  SELECT * FROM users WHERE username = ${username}
</select>
  1. 验证和清理输入

虽然MyBatis本身提供了很好的防御措施,但在某些情况下,你可能需要对用户输入进行额外的验证和清理。例如,你可以使用Java的库如Apache Commons Validator来验证输入数据。

1
2
3
4
5
6
7
import org.apache.commons.validator.routines.EmailValidator;

public void validateEmail(String email) {
    if (!EmailValidator.getInstance().isValid(email)) {
        throw new IllegalArgumentException("Invalid email address");
    }
}
  1. 使用MyBatis的XML映射文件或注解配置时,确保不拼接SQL语句

确保不要在Mapper XML文件中或通过注解拼接SQL语句。例如,不要在XML映射文件中这样做:

1
2
3
<select id="selectUsers" resultType="User">
  SELECT * FROM users WHERE username = '${username}' AND status = #{status}
</select>
  1. 限制数据类型和范围

在数据库层面和应用程序层面都应限制数据类型和范围。例如,如果你知道某个字段应该是整数,那么在数据库中设置该字段为整型,并在应用程序中验证输入确保其为整数。

  1. 使用ORM框架的高级功能

MyBatis支持动态SQL,如<if><choose><when><otherwise>等标签,这些可以安全地用来构建动态查询而不会引起SQL注入。例如:

1
2
3
4
5
6
7
<select id="findActiveUsers" resultType="User">
  SELECT * FROM users
  WHERE status = 'ACTIVE'
  <if test="username != null">
    AND username LIKE #{username}
  </if>
</select>