0%

JDK 7 中 switch 支持 String 的底层实现剖析

在 JDK 7 之前,switch 语句仅支持整型相关类型(如 byteshortintchar 及对应的包装类,以及枚举 enum)。JDK 7 引入了对 String 类型的支持,这一特性并非通过虚拟机层面的改进实现,而是编译器的语法糖—— 通过对字符串的哈希值和 equals 方法进行处理,间接转换为整型判断。本文将深入解析其底层实现原理。

switch 支持 String 的核心思路

switch 语句的本质是基于整数的跳转表(jump table),通过比较整数常量值实现分支跳转。由于字符串不是整数类型,编译器需要将字符串转换为整数形式处理,核心步骤如下:

  1. 计算字符串的哈希值:利用 String.hashCode() 方法将字符串转换为整数(哈希值);
  2. 处理哈希冲突:由于不同字符串可能有相同哈希值(哈希冲突),需通过 equals() 方法二次验证;
  3. 转换为整型 switch:将字符串的分支判断转换为基于哈希值的整型 switch 语句。

代码示例与反编译分析

原始代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SwitchStringDemo {
public void testSwitch(String gender) {
switch (gender) {
case "男":
System.out.println("男");
break;
case "女":
System.out.println("女");
break;
default:
System.out.println("未知");
}
}
}
阅读全文 »

Spring MVC 异常处理详解:三种核心方式与实战指南

在 Spring MVC 应用中,异常处理是保障系统稳定性和用户体验的关键环节。Spring MVC 提供了 @ExceptionHandlerHandlerExceptionResolver@ControllerAdvice + @ExceptionHandler 三种灵活的异常处理机制,覆盖从 “局部 Controller 异常” 到 “全局应用异常” 的全场景。从 “原理→实现→适用场景” 三个维度,彻底讲透 Spring MVC 异常处理的设计与实践。

核心概念:Spring MVC 异常处理流程

Spring MVC 的异常处理由 DispatcherServlet 主导,当 Controller 方法执行抛出异常时,DispatcherServlet 会调用 processHandlerException 方法,遍历所有 HandlerExceptionResolver(异常解析器),直到找到能处理该异常的解析器,最终生成错误响应(视图或 JSON)。

核心源码:DispatcherServlet#processHandlerException

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
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {

ModelAndView exMv = null;
// 遍历所有异常解析器,寻找能处理当前异常的解析器
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) { // 找到匹配的解析器,终止循环
break;
}
}

if (exMv != null) {
// 处理异常视图(如设置默认视图名、暴露错误信息)
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
if (!exMv.hasView()) {
exMv.setViewName(getDefaultViewName(request));
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}

// 无解析器处理,直接抛出异常
throw ex;
}
阅读全文 »

Spring MVC 拦截器详解:从原理到实践

拦截器(Interceptor)是 Spring MVC 提供的核心功能之一,用于在请求处理的不同阶段进行拦截并执行自定义逻辑(如权限校验、日志记录、性能监控等)。它与 Servlet 过滤器(Filter)类似,但更贴合 Spring MVC 的生命周期,使用更灵活。从 “拦截器与过滤器的区别→拦截器的使用→执行原理→实战场景” 全面解析 Spring MVC 拦截器。

拦截器与过滤器的核心区别

虽然拦截器和过滤器都能实现请求拦截,但两者在技术归属、执行时机、拦截范围等方面有本质区别:

特性 拦截器(Interceptor) 过滤器(Filter)
技术归属 Spring MVC 框架提供 Servlet 规范提供(Java EE 原生)
执行时机 在 DispatcherServlet 内部执行 在 DispatcherServlet 之前执行
拦截范围 仅拦截 Spring MVC 管理的请求(如 @RequestMapping 标注的方法) 拦截所有进入 Web 容器的请求(包括静态资源、JSP 等)
底层实现 基于 Java 反射机制 基于函数回调
生命周期管理 由 Spring 容器管理,可注入 Spring Bean 由 Web 容器管理,无法直接使用 Spring 资源
方法粒度 可精确到 Controller 方法级别 仅能到 URL 级别

拦截器的核心接口与方法

Spring MVC 拦截器通过 HandlerInterceptor 接口定义核心行为,包含三个关键方法,分别对应请求处理的不同阶段:

阅读全文 »

Spring MVC 返回 JSON 详解:从原理到自定义配置

在前后端分离架构中,Spring MVC 需频繁返回 JSON 格式数据(而非传统视图),核心依赖 @ResponseBody 注解与 HttpMessageConverter 机制。从 “快速实现→底层原理→自定义消息转换” 三个维度,彻底讲透 Spring MVC 如何处理 JSON 数据交互。

快速实现:返回 JSON 数据的 2 个核心步骤

Spring MVC 返回 JSON 只需 “添加依赖 + 标注注解”,无需复杂配置,适用于 90% 以上的常规场景。

步骤 1:添加 JSON 解析依赖(Jackson)

Spring MVC 默认使用 Jackson 作为 JSON 解析工具,需添加 jackson-databind 依赖(包含 jackson-corejackson-annotations):

1
2
3
4
5
6
<!-- Maven 依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> <!-- 推荐使用最新稳定版 -->
</dependency>
  • 依赖作用:提供 JSON 与 Java 对象的互转能力,Spring MVC 会自动检测该依赖,并注册 MappingJackson2HttpMessageConverter(JSON 消息转换器)。

步骤 2:使用 @ResponseBody 标注方法

在 Controller 方法上添加 @ResponseBody 注解,Spring MVC 会自动将方法返回的 Java 对象(如 UserList<User>)转换为 JSON 字符串,并设置响应头 Content-Type: application/json

实战示例:返回单个对象与集合
阅读全文 »

MySQL 查询深度解析:执行顺序、高级排序与 NULL 值处理

MySQL 查询是数据库操作的核心,理解其执行机制、掌握高级排序技巧及正确处理 NULL 值,能显著提升查询效率和准确性。本文基于查询执行顺序,详解高级用法及常见陷阱。

MySQL 查询的执行顺序

MySQL 执行 SELECT 语句时,并非按语句书写顺序执行,而是遵循固定的内部逻辑流程。正确理解执行顺序,是优化查询和排查问题的基础。

执行顺序详解(从先到后)

  1. FROM 子句:确定查询的数据来源(表、视图或子查询),是查询的起点。
    例:FROM employees 表示数据来自 employees 表。
  2. WHERE 子句:对 FROM 获取的原始数据进行行级筛选,排除不满足条件的记录(在分组前执行)。
    例:WHERE department = 'Sales' 筛选出销售部门的记录。
  3. GROUP BY 子句:将 WHERE 筛选后的结果按指定字段分组(相同值的记录归为一组)。
    例:GROUP BY department 按部门分组。
  4. 聚集函数计算:对每个分组应用聚集函数(SUMMAXCOUNT 等),生成分组的统计结果。
    例:COUNT(employee_id) 计算每个部门的员工数。
  5. HAVING 子句:对分组后的结果进行筛选(在分组后执行,可使用聚集函数)。
    例:HAVING COUNT(employee_id) > 10 筛选出员工数超过 10 人的部门。
  6. 计算表达式:处理查询中的算术运算或函数(如 salary * 1.1UPPER(name))。
  7. SELECT 子句:提取需要返回的字段(或表达式结果),此时才确定最终输出的列。
  8. ORDER BY 子句:对 SELECT 提取的结果按指定字段排序(ASC 升序,DESC 降序)。

示例:执行顺序验证

1
2
3
4
5
6
7
8
SELECT 
department,
COUNT(employee_id) AS emp_count -- 步骤7:提取字段
FROM employees -- 步骤1:数据来源
WHERE hire_year >= 2020 -- 步骤2:筛选2020年后入职的员工
GROUP BY department -- 步骤3:按部门分组
HAVING emp_count > 5 -- 步骤5:筛选员工数>5的部门
ORDER BY emp_count DESC; -- 步骤8:按员工数降序

执行流程:

  1. employees 表获取所有记录;
  2. 筛选出 2020 年及以后入职的员工;
  3. department 分组;
  4. 计算每个部门的员工数(emp_count);
  5. 保留 emp_count > 5 的分组;
  6. 无额外表达式计算;
  7. 提取 departmentemp_count
  8. emp_count 降序排序。

高级排序:ORDER BYCASE 表达式

ORDER BY 支持静态字段排序,结合 CASE 表达式可实现动态排序逻辑,根据条件调整排序依据。

语法:ORDER BY CASE ... END

阅读全文 »