这个注释是在数组上还是在元素上键入数组?

时间:2018-05-10 13:02:26

标签: java annotations

看看这个简单的代码。

try (@Foo Stream<@Bar Baz> foo = blabla) { }

我们知道@Bar正在注释Baz@Foo正在注释Stream(我已经写了类似的例子here, compile it online!)。< / p>

但这段代码怎么样?

void whatever(@Foo String[] args) { }

我们在String[]注明了@Foo(无论注释是什么,它对这个问题都不重要)。

我的问题是, @FooString上有String[]注释?

确定注释的目标非常重要,因为有时我们会使用@NotNull之类的注释来表示类型的无效性,@NotNull List<String>表示永远不为空的列表是包含一些可能为空的字符串List<@NotNull String>表示一个列表,该列表可能为null,但成员永远不为空。

一个可能的用例:我需要@NotNull显示args不为空,而另一个@NotNull显示args的成员也不为空?我需要同时注释它们。如果argsjava.util.List,我可以使用@NotNull List<@NotNull String>。但是args是一个数组 - 而且我不知道注释如何影响args的类型。

2 个答案:

答案 0 :(得分:2)

在数组级别之前定义@NonNull似乎可以解决问题(至少对于Checker Framework):

import org.checkerframework.checker.nullness.qual.NonNull;

class App {
    void foo() {
        String @NonNull [] bar;
        bar = null; // NOK
        bar = new String[1];
        bar[0] = null; // NOK
    }
}

导致两个错误(参见live demo):

| No. | Type  |                                 Description                                 | Line | Column |
|-----|-------|-----------------------------------------------------------------------------|------|--------|
|   1 | error | Error: [assignment.type.incompatible] incompatible types in assignment.     |    6 |     15 |
|     |       |   found   : null                                                            |      |        |
|     |       |   required: @Initialized @NonNull String @UnknownInitialization @NonNull [] |      |        |
|   2 | error | Error: [assignment.type.incompatible] incompatible types in assignment.     |    8 |     18 |
|     |       |   found   : null                                                            |      |        |
|     |       |   required: @Initialized @NonNull String                                    |      |        |

要回答您的实际问题,请参阅specification, §9.7.4

@C int @A [] @B [] f;
     

@A适用于数组类型int[][]@B适用于其组件类型   int[]@C适用于元素类型int

所以@Foo String[] args实际上是注释String(读作:非空字符串的可能为空的数组)。

答案 1 :(得分:2)

问题有两个可能的答案&#34;在@Foo String[] args中,@Foo注释是什么?&#34;。

  • 如果@Foo类型注释(即Foo的定义是使用@Target(ElementType.TYPE_USE)元注释的),那么{{ 1}}适用于元素类型@Foo,并且您声明了一个String数组。

  • 如果@Foo String声明注释(其定义未使用Foo进行元注释),则@Target(ElementType.TYPE_USE)适用于整个声明@Foo。这对于正式的参数来说并不常见。

在该位置,String[] args注释不能引用数组类型@Foo

(其他回复特别为String[]提供了有用的答案,但没有回答原始问题。)