使用新的Java 8的ElementType.TYPE_USE
选项,可以对(多维)数组的每个组件进行注释。例如,现在我可以在一个简单的字符串数组中注释整个类型String[]
和内部组件类型String
。所以我希望这样做:
@MyAnnotation(0) private static (@MyAnnotation(1) String) [] strs0;
像以前一样,我把注释放在类型之前。如果在这些表达式中允许括号,那么它将完美地工作。然而,Java似乎选择了另一种方法,这导致了一些问题。我必须写:
@MyAnnotation(0) private static String @MyAnnotation(1) [] strs1;
并假设@MyAnnotation(0)
适用于整个字段, @MyAnnotation(1)
仅适用于 String
,尽管它是之后的类型String
。这是对这一声明的正确解释吗?
因为如果是这样,那么反射解析就会出现严重错误。例如,使用以下声明:
@MyAnnotation(0) private static String @MyAnnotation(1) [] @MyAnnotation(2) [] @MyAnnotation(3) [] strs2;
假设@MyAnnotation(0)
是指整个字段,那么@MyAnnotation(3)
是指String[][]
组件,@MyAnnotation(2)
是指String[]
组件,最后@MyAnnotation(1)
是指String
组件。然而,当我们用以下代码解析它时:
Field field = Main.class.getDeclaredField("strs2");
AnnotatedArrayType aat = (AnnotatedArrayType) field.getAnnotatedType();
printAll(aat.getAnnotations());
while (aat.getAnnotatedGenericComponentType() instanceof AnnotatedArrayType) {
aat = (AnnotatedArrayType) aat.getAnnotatedGenericComponentType();
printAll(aat.getAnnotations());
}
我们将看到:
@MyAnnotation(1)
@MyAnnotation(2)
@MyAnnotation(3)
与我们期望的顺序相反({ 3, 2, 1 }
)。如果我们要迭代矩阵的元素,同时迭代抛出注释,将它们应用到相应的元素上,这就特别麻烦了。当我们迭代时,我们从最后一个关卡到第一个关卡,也就是说,我们遍历所有String[][][]
获得每个String[][]
。然后我们遍历每个String[][]
并获得所有String[]
。最后,我们迭代String[]
,得到每个String
。
这些反思(没有双关语的意思)让我思考我对这些TYPE_USE例子的含义的解释是否正确。当然,我可以只迭代一次矩阵,堆叠注释对,然后重新工作,但是Java总是如此简单和优雅,我一定错过了一些东西,可能是我们声明表达式的方式,或者是整个事情的解释方式。
我想要注释每个数组组件的原因是为了创建一个验证框架。它在List<>
类型上完美地工作,使用AnnotatedParameterizedType
。我可以写@Required List<@Required List<@Required Map<@Required String, @Required String>>> data
,并在正确的其他检索这些注释,没有任何问题。奇怪的是,原始数组的行为似乎不同…
更多细节,更新答案信息
例如,当我们写
@A List<@B ArrayList<@C LinkedList<@D Integer>>> matrix;
很明显,@A
与最外层的List
、@B -> ArrayList
、@C -> LinkedList
和@D -> Integer
有关,因为注释就在声明的类型之前。但是当我们写
@A int @B [] @C [] @D [] matrix;
乍一看,注释似乎在类型之后,例如:
@A (((int @B) [] @C) [] @D) [] matrix;
所以@B -> int
, @C -> int[]
, @D -> int[][]
。问题是,我们必须这样看:
@A int (@B []) (@C []) (@D []) matrix;
然后如果我们知道当调用矩阵[x]时,我们得到一个int[][],所以@B -> int[][],而只有矩阵[x][y][z]给出一个int,所以@D -> int。因此,相关关系是在使用字段,而不是声明指令。
这与List
s不同,因为@D
注释就在它所引用的Integer
类型之前。这种差异可能只对泛型列表有意义,而可能不会出现在其他常见的泛型场景中。
我看不出有什么问题。给定一个String[][][]
,您将其描述为一个数组,其中组件是String[][]
。这也是一个数组,其中组件是String[]
。这也是一个数组,其中组件是String
。
可以假设
@MyAnnotation(0)
指的是整个字段@MyAnnotation(3)
为String[][]
组件,@MyAnnotation(2)
为String[]
组件,最后为@MyAnnotation(1)
组件
我不同意。那么,给定一个
@MyAnnotation(0) private static String @MyAnnotation(1) [] @MyAnnotation(2) [] @MyAnnotation(3) [] strs2;
您将其描述为带有@MyAnnotation(0)
注释的字段,该字段是数组类型,其中组件是带有@MyAnnotation(1)
注释的String[][]
。这也是一个数组,其中的组件是带有@MyAnnotation(2)
注释的String[]
。这也是一个数组,其中的组件是带有@MyAnnotation(3)
注释的String
。
迭代时,从的最后一级到第一级,也就是我们遍历所有String[][][]获取每个String[][]。然后再看一遍每个String[][]并获取所有String[]。最后我们进行迭代字符串[],并获取每个String