注释如何防止数组参数的突变?

fla*_*kes 15 java arrays annotations immutability

我理解注释是不可变的,但是,Java中的数组本身并不是不可变的.运行测试后,我注意到从注释参数返回的数组可以变异,但它不会影响源数组:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface ArrayAnnotation {
    String[] value() default {};
}

@ArrayAnnotation({"foo"})
public class Main {
    public static void main(String[] args) {
        ArrayAnnotation test = Main.class.getAnnotation(ArrayAnnotation.class);

        String[] test0 = test.value();
        test0[0] = "bar";
        System.out.println(test0[0]);

        String[] test1 = test.value();
        System.out.println(test1[0]);
    }
}
Run Code Online (Sandbox Code Playgroud)

这打印:

bar
foo
Run Code Online (Sandbox Code Playgroud)

幕后发生了什么事?在每次调用期间是否只发生了一个数组副本value(),或者它是否更复杂?

cac*_*co3 13

在每次调用value()时是否只发生了一个数组副本,还是更复杂?

是的,数组被复制.


注释是一种特殊interface类型.(JLS)

它们Proxy在运行时由某些类实现.如果设置断点,则可以调试它Proxy.newProxyInstance().

注释的调用被AnnotationInvocationHandler拦截,后者复制数组:

if (result.getClass().isArray() && Array.getLength(result) != 0)
     result = cloneArray(result);
Run Code Online (Sandbox Code Playgroud)

  • 啊,非常酷!我的IDE调试器中的逐步进入功能不会为`values()`触发任何操作,但是直接在`AnnotationInvocationHandler`代理中添加一个断点就可以了!非常感谢! (2认同)

Pet*_*rey 5

你是对的,每次都会返回一份副本以确保它没有被更改.

在Java的未来版本中,可能会优化此副本.