百度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?
在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 存储变量副本,每个线程对副本的修改互不影响。
二、工作原理
- 存储结构
- 每个线程内部维护一个
ThreadLocalMap,以 ThreadLocal 实例为键、变量副本为值的映射表。
ThreadLocalMap 采用弱引用存储 ThreadLocal 键,避免内存泄漏。
- 核心方法
set(T value):将值存入当前线程的 ThreadLocalMap。
get():从当前线程的 ThreadLocalMap 获取值。
remove():删除当前线程的 ThreadLocalMap 中的值。
- 生命周期
三、典型应用场景
- 线程上下文传递
- 在跨线程调用中传递请求上下文(如用户信息、请求ID)。
- 示例:Spring MVC 中通过
RequestContextHolder 获取请求信息。
- 数据库连接管理
- 每个线程独立管理数据库连接(如 MyBatis 的
SqlSession)。
- 避免线程间连接冲突。
- 事务管理
- 手动管理事务上下文,保证事务隔离性。
- 示例: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标准):
- **默认隔离级别(
Isolation.DEFAULT)**
使用数据库的默认隔离级别,如MySQL的可重复读(REPEATABLE_READ),Oracle的读已提交(READ_COMMITTED)。
- **读未提交(
Isolation.READ_UNCOMMITTED)**
允许读取未提交的数据,可能导致脏读、不可重复读和幻读问题。
- **读已提交(
Isolation.READ_COMMITTED)**
避免脏读,但可能仍出现不可重复读和幻读。
- **可重复读(
Isolation.REPEATABLE_READ)**
避免脏读和不可重复读,但可能仍出现幻读(如InnoDB通过多版本并发控制实现)。
- **串行化(
Isolation.SERIALIZABLE)**
最高隔离级别,完全避免脏读、不可重复读和幻读,但性能最低(通过表级锁实现)。
Maven 遇到Jar包冲突怎么解决?
在 Maven 项目中遇到 Jar 包冲突时,可采用以下几种高效解决方法:
- 基础排除法( 标签)
适用场景:排除直接依赖中的传递性冲突包。
操作示例:
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>
|
- 验证和清理输入
虽然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");
}
}
|
- 使用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>
|
- 限制数据类型和范围
在数据库层面和应用程序层面都应限制数据类型和范围。例如,如果你知道某个字段应该是整数,那么在数据库中设置该字段为整型,并在应用程序中验证输入确保其为整数。
- 使用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>
|