JSP 的 Scriptlet 和 Declaration 标签有什么区别?

Scriptlet(脚本段)和 Declaration(声明标签)是 JSP 脚本元素的核心,但编译位置、作用域、使用场景完全不同,核心区别如下:

维度 Scriptlet(<% ... %> Declaration(<%! ... %>
编译位置 嵌入 Servlet 的_jspService()方法中 位于 Servlet 类的_jspService()方法外(类级别)
变量作用域 局部变量(仅当前请求的_jspService()方法有效) 成员变量(Servlet 实例级别,所有请求共享)
方法定义 不能定义方法(仅能调用方法) 可定义成员方法(整个 Servlet 实例可调用)
生命周期 随每次请求创建 / 销毁(局部变量) 随 Servlet 实例创建 / 销毁(成员变量)
线程安全 局部变量无线程安全问题(每个请求独立) 成员变量存在线程安全问题(多请求共享)
常用场景 处理单次请求的逻辑(参数处理、条件判断、循环) 定义全局常量、工具方法、共享计数器(需谨慎)

关键示例对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%-- Scriptlet:局部变量,每次请求独立 --%>
<%
int num = 1; // 局部变量,每次请求都会重新赋值为1
num++;
out.print("Scriptlet num:" + num); // 每次输出都是2
%>

<%-- Declaration:成员变量,所有请求共享 --%>
<%!
int num = 1; // 成员变量,多次请求会累加
public int add() { return num++; }
%>
<%
out.print("<br>Declaration num:" + add()); // 第一次输出2,第二次3,依此类推
%>

注意:Declaration 的成员变量因多线程共享,易引发线程安全问题(如计数器错误),除非确需全局共享,否则优先使用 Scriptlet 或其他作用域(如 session、application)。