技术面试知识地图:Java、C++、数据库与Web开发核心考点全梳理
简介:这份东软面试题汇总面向具备一定编程基础、有志于加入东软或其他IT企业的研发求职者,系统整理了招聘中涉及的技术考核要点。内容覆盖Java、C++、C#等编程语言,以及ASP.NET、JavaScript等Web开发方向,并延伸至SQL Server数据库、线程与进程、二叉树与链表等数据结构知识,还涉及设计模式、内存管理与垃圾回收等进阶话题,可帮助读者提前把握面试重点、模拟真实场景并加深对底层原理的理解。资源包共1个PDF文件,约560KB,内容以问答形式呈现,既有堆栈区别、多态实现、索引与视图、MVC等基础题,也有环形链表检测、final与finally区别等细节追问,部分题目附有面试现场对话与思路分析。目前已有87人学习,适合用于查漏补缺与临场思路训练。
1. 技术面试知识地图:从 Java 基础到数据库与 Web 开发的完整复习框架
很多人复习技术面试题时,习惯按语言分块背:Java 背一遍、C++ 背一遍、数据库再背一遍。但真正梳理下来会发现,面试官考的从来不是孤立的语言细节,而是一张交叉的知识网——同一道题可能同时涉及数据结构、内存模型和面向对象设计。这份汇总覆盖了 Java、C++、C#、数据库、Web 开发、操作系统、数据结构等多个方向,题目跨度大、层次分明,适合有一定编程基础、正在系统准备技术面试的人拿来当复习地图用。它把散落在各处的考点串成了一条线:语言基础是入口,数据结构和算法是骨架,数据库和 Web 开发是落地场景,而面向对象思想和内存管理则是贯穿始终的底层逻辑。下面按模块逐一梳理重点、难点和容易翻车的地方。
2. 语言基础三大件:Java、C++ 与 C# 的核心考点对比
2.1 面向对象的四条主线:封装、继承、多态、抽象
不管面试官问的是 Java、C++ 还是 C#,面向对象的问题永远绕不开这四个词。但很多人背得出定义,却说不清它们之间的关系和实现方式。
封装是把数据和操作数据的方法包在一起,对外只暴露必要的接口。继承让子类拥有父类的属性和方法,实现代码复用。多态是同一个操作作用于不同类的实例产生不同结果,分编译时多态(重载)和运行时多态(重写)。抽象则是提取共性、忽略差异,通过抽象类或接口来实现。
梳理下来会发现,面试中最容易翻车的是多态。面试官常追问:“重载是多态吗?”答案是:重载属于编译时多态,但严格来说它只是多态的一种表现形式,真正体现多态威力的是运行时多态——父类引用指向子类对象,运行时根据实际类型决定调用哪个方法。
| 概念 | 实现方式 | 绑定时机 | 典型关键字 |
|---|---|---|---|
| 编译时多态 | 方法重载 | 编译期 | overload |
| 运行时多态 | 方法重写 + 向上转型 | 运行期 | override、virtual |
| 封装 | 访问修饰符 | — | private、protected、public |
| 抽象 | 抽象类 / 接口 | — | abstract、interface |
C++ 中多态的实现依赖虚函数。父类指针指向子类对象时,只有将父类方法声明为virtual,才能实现动态绑定。纯虚函数(virtual 函数名 = 0)则构成抽象类,不能实例化,必须由子类实现。
class Shape { public: virtual double area() = 0; // 纯虚函数,Shape 是抽象类 }; class Circle : public Shape { double r; public: Circle(double radius) : r(radius) {} double area() override { return 3.14159 * r * r; } // 运行时多态 };这段代码里,Shape定义了接口area(),Circle给出具体实现。当用Shape*指向Circle对象并调用area()时,实际执行的是Circle的版本——这就是运行时多态。参数r是半径,override关键字让编译器检查重写签名是否正确,避免因参数类型不匹配导致多态失效。
Java 的接口和 C++ 的虚类有相似之处,但区别也很明显:Java 接口中所有方法默认是public,属性默认是public static,一个类可以实现多个接口,弥补了单继承的限制。C++ 的虚类则可以有实现代码,支持多继承,但也因此带来菱形继承等复杂问题。
2.2 final、finally、finalize 与 const 的辨析
这三个词长得像,考的频率极高,但含义完全不同。
final是修饰符,用在变量上表示常量(必须初始化,不能重新赋值),用在方法上表示不能被子类重写,用在类上表示不能被继承。finally是异常处理的一部分,配合try-catch使用,不管 try 块是否正常执行、catch 是否触发,finally 中的代码都会执行,通常用来关闭连接、释放资源。finalize是 Object 类的方法,在对象被垃圾回收前调用,但执行时机不确定,实践中不推荐依赖它做资源清理。
C++ 中对应的概念是const。const变量必须在定义时初始化,const成员函数不能修改对象状态。和 Java 的final相比,const的语义更丰富,可以修饰指针本身、指针指向的内容,或者两者都修饰。
注意:面试中如果被问到“final 变量能不能在静态块中初始化”,答案是肯定的——对于静态 final 变量,可以在静态初始化块中赋值,这不算重新赋值。
2.3 异常处理机制:Error 与 Exception 的分界线
Java 的异常体系以Throwable为根,下面分两支:Error和Exception。Error表示系统级错误,比如OutOfMemoryError、StackOverflowError,程序通常无法处理,也不应该尝试捕获。Exception则是程序可以捕获和处理的异常,又分受检异常(checked)和非受检异常(unchecked,即RuntimeException及其子类)。
C++ 的异常处理没有受检和非受检之分,所有异常都可以抛出和捕获,但 C++ 中如果异常没有被捕获,程序会直接终止。C# 的异常体系与 Java 类似,但所有异常都是非受检的,不需要在方法签名中声明。
实际编码中,异常处理的关键不是记住分类,而是知道什么场景该抛、什么场景该捕、什么场景该记录日志后继续。面试官更看重的是你对异常粒度的把握:数据库连接失败该回滚并提示用户重试,用户输入格式错误该返回明确的校验提示,服务器崩溃则只能记录日志并返回通用错误页。
3. 数据结构与算法:链表、二叉树与排序的复习重点
3.1 环形链表检测:从暴力法到快慢指针
“如何检测一个链表是否有环”是面试中的经典题,也是区分度很高的一道题。最直觉的做法是遍历链表,把每个节点的引用存入一个集合,每次访问新节点时检查是否已存在于集合中。如果存在,说明有环;如果遍历到 null,说明无环。这种方法时间复杂度 O(n),空间复杂度 O(n)。
但面试官往往会追问:“如果链表很大,内存有限,怎么做?”这时候就需要快慢指针法:设置两个指针,慢指针每次走一步,快指针每次走两步。如果链表有环,快指针一定会在环内追上慢指针;如果无环,快指针会先到达 null。
public boolean hasCycle(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; // 慢指针走一步 fast = fast.next.next; // 快指针走两步 if (slow == fast) return true; // 相遇说明有环 } return false; // 快指针到达末尾,无环 }这段代码的核心在于:fast每次比slow多走一步,如果存在环,两者必然在环内相遇。参数head是链表头节点,返回布尔值表示是否有环。空间复杂度降到了 O(1),不需要额外的集合存储。
梳理下来会发现,这道题的延伸问题也值得准备:如何找到环的入口节点?方法是相遇后,让一个指针回到头节点,然后两个指针每次各走一步,再次相遇的位置就是环的入口。
3.2 二叉树与完全二叉树的性质
二叉树是数据结构面试的高频考点。完全二叉树的定义是:深度为 k、有 n 个节点的二叉树,当且仅当其每一个节点都与深度为 k 的满二叉树中编号从 1 到 n 的节点一一对应时,称为完全二叉树。简单说,就是除了最后一层,其他层都是满的,且最后一层的节点都靠左排列。
面试中常见的考法是画几棵树让你辨认哪个是完全二叉树。容易混淆的是满二叉树和完全二叉树:满二叉树要求每一层都是满的,完全二叉树只要求最后一层可以不满,但必须从左到右连续排列。
B- 树是另一种常考结构,主要用于磁盘存储和数据库索引。与二叉树不同,B- 树的每个节点可以存储多个关键字,并且有多个子节点。B- 树的特点是所有叶子节点在同一层,查找路径长度一致,适合减少磁盘 I/O 次数。
3.3 排序算法分类与适用场景
面试中问排序,不会只问“有哪些排序方法”,而是会追问“什么场景用哪种”。插入排序适合小规模或基本有序的数据;快速排序平均性能最好,但最坏情况退化到 O(n²);归并排序稳定且最坏也是 O(n log n),但需要额外空间;堆排序原地排序且最坏 O(n log n),但常数因子较大;基数排序适合整数且范围不大的场景。
| 排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
|---|---|---|---|---|
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 |
| 快速排序 | O(n log n) | O(n²) | O(log n) | 不稳定 |
| 归并排序 | O(n log n) | O(n log n) | O(n) | 稳定 |
| 堆排序 | O(n log n) | O(n log n) | O(1) | 不稳定 |
| 基数排序 | O(d(n+k)) | O(d(n+k)) | O(n+k) | 稳定 |
最容易忽略的是稳定性。如果面试官问“给订单按金额排序,金额相同的按时间排序”,就需要稳定排序,或者用额外字段做二级排序。快速排序不稳定,归并排序稳定,这个区别在实际业务中很关键。
4. 数据库核心:索引、视图、游标与 JDBC 操作流程
4.1 索引、视图、游标的概念与使用场景
索引依附于基表存在,是加快查询的有效手段。可以类比成书的目录:没有目录,找内容要一页页翻;有了目录,直接定位。但索引不是越多越好,因为每次插入、更新、删除都需要维护索引,会降低写入性能。面试中常问“什么字段适合建索引”,答案是:经常出现在 WHERE 子句、JOIN 条件、ORDER BY 中的字段,且区分度高。
视图是从一个或多个基表(或视图)导出的虚表,不存储实际数据,只保存查询定义。视图的作用是简化复杂查询、控制数据访问权限、提供数据独立性。游标是系统为用户开设的数据缓冲区,存放 SQL 语句的执行结果,用户可以通过游标逐一获取记录。游标在存储过程中用得比较多,但性能开销较大,能不用尽量不用。
4.2 SQL 语句分类与 JDBC 操作五步
SQL 语句按功能分四类:SELECT查询、INSERT插入、UPDATE更新、DELETE删除。面试中常考的是复杂查询,比如“查询每个部门工资最高的员工”“查询连续登录三天的用户”等。
JDBC 操作数据库的标准流程分五步:加载驱动程序、建立数据库连接、发送 SQL 语句、处理事务、管理连接。每一步都有容易出错的地方。
Connection conn = null; PreparedStatement ps = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 1. 加载驱动 conn = DriverManager.getConnection(url, user, password); // 2. 建立连接 conn.setAutoCommit(false); // 3. 开启事务 ps = conn.prepareStatement("UPDATE account SET balance = balance - ? WHERE id = ?"); ps.setDouble(1, amount); // 参数1:扣款金额 ps.setInt(2, fromId); // 参数2:转出账户 ps.executeUpdate(); conn.commit(); // 4. 提交事务 } catch (Exception e) { if (conn != null) conn.rollback(); // 回滚 } finally { if (ps != null) ps.close(); // 5. 关闭资源 if (conn != null) conn.close(); }这段代码展示了 JDBC 事务处理的标准写法。setAutoCommit(false)关闭自动提交,手动控制事务边界。PreparedStatement使用占位符?防止 SQL 注入。finally块确保资源被关闭,避免连接泄漏。参数url、user、password分别对应数据库地址、用户名和密码。
4.3 存储过程与多外键表设计
存储过程是一组预编译的 SQL 语句,存储在数据库中,可以通过名称调用。优点是减少网络传输、提高执行效率、封装业务逻辑;缺点是移植性差、调试困难。面试中如果被问到“有没有用过存储过程”,可以结合具体场景说:比如批量数据处理、定时任务、复杂报表生成等。
一个表设置多个外键是完全可以的。外键对应相关表的主键,内容只能是对应主键的值。如果主键发生变化,外键所在的记录会按照定义时指定的规则进行保留、删除或更新。常见规则有CASCADE(级联)、SET NULL(置空)、RESTRICT(拒绝)。设计时要注意外键约束对性能的影响,高并发写入场景下可能需要权衡。
5. Web 开发与框架:MVC、Struts 与三层架构的落地要点
5.1 MVC 模式与三层架构的区别
MVC 是 Model-View-Controller 的缩写,Model 负责数据和业务逻辑,View 负责展示,Controller 负责接收请求和调度。三层架构是 Web 服务器、应用服务器、数据库服务器的划分,或者更常见的表述是表现层、业务逻辑层、数据访问层。
两者的关系容易混淆。MVC 是表现层的设计模式,关注的是请求如何被处理、数据如何被展示。三层架构是系统级的架构划分,关注的是职责分离和部署灵活性。一个典型的 Java Web 项目可能同时使用 MVC 和三层架构:Struts 或 Spring MVC 负责 Controller 层,Service 层处理业务逻辑,DAO 层负责数据访问。
5.2 Struts 中 Action 与 ActionForm 的关系
Struts 是经典的 Java Web 框架,面试中常问 Action 和 ActionForm 的关系。ActionForm 负责封装请求参数和表单数据,Action 负责处理业务逻辑和返回结果。一个 Action 通常对应一个 ActionForm,因为 Action 的配置文件中name属性指向一个 ActionForm,而每个 Action 标签只能有一个name属性。
但这不意味着 ActionForm 和 Action 是一对一绑死的。多个 Action 可以共用同一个 ActionForm,只要表单字段一致。实际项目中,ActionForm 的设计要尽量通用,避免为每个 Action 都创建一个新的 Form 类。
5.3 页面框架与 JavaScript 导航实现
在 Web 前端开发中,页面框架的设计直接影响可维护性。常见的做法是把页面分为 sidebar、header、footer、content 四部分,其中 sidebar、header、footer 在每个页面中重复出现,可以抽成公共组件放在配置文件中,每个页面引用即可。content 部分才是每个页面独有的内容。
JavaScript 在导航栏中常用于实现弹出菜单、下拉列表、动态高亮当前菜单项等功能。实现时要注意事件绑定方式,避免内存泄漏。现代前端开发中,这些功能通常由框架(如 Vue、React)接管,但理解原生 JavaScript 的实现原理仍然有助于排查问题和优化性能。
6. 易漏点与易错点:面试复习中最容易翻车的五个地方
6.1 易漏点一:把重载当成运行时多态
为什么漏:很多教材和笔记在讲多态时,把重载和重写放在一起讲,导致复习时容易混为一谈。
怎么补:记住一条判断标准——看方法调用的绑定时机。编译期就能确定调用哪个方法的,是编译时多态(重载);必须等到运行时根据对象实际类型才能确定的,是运行时多态(重写)。面试中如果被追问“重载是多态吗”,可以回答:“重载是编译时多态的一种形式,但通常说的多态指的是运行时多态。”
6.2 易漏点二:混淆栈和堆的分配方式
为什么漏:栈和堆的概念在数据结构、操作系统、编程语言三个层面都有涉及,容易张冠李戴。
怎么补:分场景记忆。在数据结构中,栈是后进先出的线性表,堆是优先队列的一种实现。在内存管理中,栈由系统自动分配和释放,存放局部变量和函数调用信息;堆由程序员手动分配和释放(C/C++),或由垃圾回收器管理(Java/C#)。面试中如果问“char *p = malloc(100)分配的内存在哪里”,答案是堆。
6.3 易漏点三:wait 和 sleep 的区别说不清楚
为什么漏:两者都能让线程暂停,但释放锁的行为不同,复习时容易只记一半。
怎么补:抓住核心区别——wait会释放对象锁,sleep不会。wait必须在同步块中调用,sleep可以在任何地方调用。wait通常配合notify或notifyAll使用,sleep到时间自动唤醒。面试中如果被问到“哪个方法能释放锁”,答案是wait。
6.4 易漏点四:数据库连接池的使用条件
为什么漏:连接池的配置参数多,复习时容易只关注“怎么配”,忽略“什么情况下连接池会失效”。
怎么补:连接池能否复用连接,取决于连接字符串是否完全一致。空格数、参数顺序、大小写不同,都会导致连接池认为是不同的连接,从而无法复用。面试中如果问“为什么连接池没有生效”,先检查连接字符串是否完全一致。
6.5 易漏点五:final 变量在静态块中初始化
为什么漏:很多人记住“final 变量必须初始化”,但忽略了静态 final 变量可以在静态块中初始化。
怎么补:区分实例 final 变量和静态 final 变量。实例 final 变量必须在声明时、构造器中或初始化块中赋值;静态 final 变量必须在声明时或静态初始化块中赋值。两者都不能在普通方法中重新赋值。
7. 复习清单与查漏补缺:从知识地图到面试现场的最后一公里
复习到后期,最怕的不是不会,而是“以为自己会了”。下面这份清单按模块列出核心考点,可以用来逐项自查。每一条都问自己三个问题:概念是什么?为什么这样设计?实际项目中怎么用?
语言基础自查清单:
| 模块 | 核心考点 | 自查标准 |
|---|---|---|
| 面向对象 | 封装、继承、多态、抽象 | 能画出类图并解释多态绑定时机 |
| 关键字 | final、finally、finalize、const | 能说出三者区别并举例 |
| 异常 | Error vs Exception、受检 vs 非受检 | 能写出自定义异常并说明使用场景 |
| 内存 | 栈 vs 堆、值类型 vs 引用类型 | 能画出内存分配示意图 |
| 线程 | wait vs sleep、同步方法 | 能写出生产者消费者模型 |
数据结构与算法自查清单:
- 链表:能手写反转链表、检测环、找环入口
- 二叉树:能说出完全二叉树、满二叉树、B- 树的区别
- 排序:能默写快速排序和归并排序,并说明稳定性
- 查找:能解释二分查找的边界条件
数据库自查清单:
- 能写出复杂 SQL:分组取 Top N、连续登录、行转列
- 能解释索引原理和失效场景
- 能说明事务的 ACID 和隔离级别
- 能写出 JDBC 事务处理的标准代码
Web 开发自查清单:
- 能解释 MVC 和三层架构的区别与联系
- 能说明 Struts 中 Action 和 ActionForm 的关系
- 能写出一个简单的用户控件或公共页面组件
- 能解释 session 和 cookie 的区别
查漏补缺的方法很简单:拿一张白纸,不看笔记,把每个模块的核心知识点默写出来。写不出来的,就是需要重点补的地方。写出来但说不清“为什么”的,是需要深入理解的地方。写出来也能说清“怎么用”的,才是真正掌握了。
我自己的习惯是,每次面试前三天,把这份清单过一遍,每个考点用一句话总结,然后对着镜子讲一遍。讲得磕巴的地方,就是还没吃透的地方。从那以后我每次复习都强制走一遍“默写—讲解—模拟追问”的流程,比单纯看笔记效率高得多。希望这份梳理能帮到你,面试顺利。
本文还有配套的精品资源,点击获取