Skip to content

数组构造 (Array Construction)

你可以使用熟悉的 Java 语法来构建数组,也可以选择性地提供初始化器,以便在构造时填充数组。如下例所示:

java
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);

// 带有初始化器的数组
int[] numbers2 = (int[]) parser.parseExpression("new int[] {1, 2, 3}").getValue(context);

// 多维数组
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
kotlin
val numbers1 = parser.parseExpression("new int[4]").getValue(context) as IntArray

// 带有初始化器的数组
val numbers2 = parser.parseExpression("new int[] {1, 2, 3}").getValue(context) as IntArray

// 多维数组
val numbers3 = parser.parseExpression("new int[4][5]").getValue(context) as Array<IntArray>

注意

目前在构造多维数组时,不支持提供初始化器。

警告

任何构造数组的表达式(例如通过 new int[4]new int[] {1, 2, 3})都 无法被编译 为字节码。详见编译器限制


补充教学

1. 数组构造 vs 内联列表

虽然 SpEL 支持数组构造,但在大多数情况下,你会发现使用 内联列表 ({}) 更加方便:

  • 语法简洁{1, 2, 3}new int[] {1, 2, 3} 简短得多。
  • 动态类型:内联列表会自动根据环境推断类型(通常是 ArrayList),而数组构造则强绑定了 Java 的原生数组类型。
  • 性能优选:正如之前的章节所说,内联列表如果是静态字面量会被缓存为单例常量。而数组构造(new 关键字)每次执行表达式都会分配新的内存空间。

2. 什么时候必须用数组构造?

尽管有性能和易用性的差异,但在某些特定场景下,数组构造是不可替代的:

  • 严格的方法签名:如果你在表达式中调用一个 Java 方法,而该方法明确要求传入 String[] 而不是 List<String>,那么你就需要用 new String[] {'a'}
  • 固定长度需求:如果你需要一个预分配大小且后续会填充值的容器(通过 setValue),new int[10] 是最直接的方式。

3. 理解“不可编译”的含义

文档中提到的“警告”非常重要。如果你的 Spring 项目开启了 SpEL 编译模式(SpelCompilerMode.IMMEDIATEMIXED),对于大部分表达式,Spring 会把它们转换成原生的 Java 字节码以获得极高性能。 但是,一旦表达式中包含 new 一个数组的操作,这部分逻辑就只能退回到“解释执行”模式。

  • 性能影响:如果这个表达式位于一个高频调用的拦截器或循环中,它会比已编译的表达式慢几个数量级。
  • 架构建议:避免在性能敏感的热点代码中使用 SpEL 动态创建数组。尽量提前在 Java 代码中准备好数组,或者直接使用内联列表。

Based on Spring Framework.