之前写参数校验的时候将字段的长度写成了一个常量,习惯了用包装类型,于是乎有了类似(以下截图只是为了复现这个问题刚特意改的)如下的代码:

常量为包装类型
常量为包装类型

结果项目编译报错,提示我这里传入的不是一个常量:

编译错误
编译错误

心想“我这个字段都用 staticfinal 修饰了,怎么就不是常量了?”带着这个“疑问”点开 @Size 注解的定义:

注解定义
注解定义

发现其中 minmax 字段的定义是 int 基本类型,并不是 Integer 包装类型,再想到 Java 中基本类型与其对应的包装类型之间的自动装箱和拆箱机制,一下就明白了。我定义的是 Integer 类型的常量,当赋值给 int 类型的字段时,Java 编译器会自动将其拆箱为 int 类型。而这个拆箱的实现方式,其实就是调用 Integer 对象的 .intValue() 方法(其他几个包装类型同理)。


所以我们定义的 Integer “常量”对编译器来说实际上是 Integer.intValue() 这样一个方法调用,明显已经不是一个常量表达式了。


知道原因后,将 Integer 修改为 int:

常量为基本类型
常量为基本类型

再来编译试试,发现这下编译通过了:

编译通过
编译通过

我们可以通过以下例子来验证上面的问题:

验证自动装箱、拆箱
验证自动装箱、拆箱

编译后通过 javap 命令查看编译后的字节码,可以看出来,自动装箱实际上就是调用的 Integer.valueOf() 方法,拆箱就是调用的 Integer.intValue() 方法:

查看编译后的字节码
查看编译后的字节码

这样也就能明白为什么将一个 Integer 常量赋值给 int 时就不是常量了。