我正在阅读the code of Guava,在其中找到了一些代码中的注释java.util.@Nullable
。我知道@Nullable
的含义,但我不理解。特别是,在包Nullable
中找不到名为java.util
的类。
拜托,有人告诉我这个java.util.@Nullable
是什么意思:
public static <T> java.util.@Nullable Optional<T> toJavaUtil(
@Nullable Optional<T> googleOptional) {
return googleOptional == null ? null : googleOptional.toJavaUtil();
}
答案 0 :(得分:37)
public static <T> java.util.@Nullable Optional<T> toJavaUtil
行是这样写的,因为通常的样式public static <T> @Nullable java.util.Optional<T> toJavaUtil
无效。这是在JLS §9.7.4中定义的:
如果类型T的注释适用于类型上下文中的类型(或类型的任何部分),并且T适用于类型上下文,则该注释不可接受,这是编译时错误
。例如,假设注释类型TA仅用
@Target(ElementType.TYPE_USE)
进行元注释。术语@TA java.lang.Object
和java.@TA lang.Object
是非法的,因为@TA最接近的简单名称被分类为程序包名称。另一方面,java.lang.@TA Object
是合法的。
org.checkerframework.checker.nullness.qual@Nullable
的类型声明为:
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
因此它适用于此规则。
当我们使用java.util
查看编译后的代码时,可以看出这种结构不会中断执行,因为软件包Optional
和类名javap -c [compiled class name]
被拆分了: >
class just.a.test.Main {
just.a.test.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static <T> java.util.Optional<T> toJavaUtil(blub.Optional<T>);
Code:
0: aload_0
1: ifnonnull 8
4: aconst_null
5: goto 12
8: aload_0
9: invokevirtual #2 // Method blub/Optional.toJavaUtil:()Ljava/util/Optional;
12: areturn
}
(blub.Optional
是一个本地类,我在其中复制了Guava代码,以获取用于反编译的最小示例) >
如您所见,注释在那里不再存在。它仅是编译器的一个标记,用于在方法返回null(以及对源代码阅读器的提示)时阻止警告,但不会将其包含在编译后的代码中。
此编译器错误也适用于以下变量:
private @Nullable2 java.util.Optional<?> o;
但是当注释另外获得目标类型ElementType.FIELD
时(如在同一JLS子句中所写),它可以被接受:
如果TA额外用
@Target(ElementType.FIELD)
进行元注释,则术语@TA java.lang.Object
在声明和类型上下文(例如字段声明@TA java.lang.Object f;
)中都是合法的。在这里,@ TA被认为适用于f的声明(而不适用于类型java.lang.Object),因为TA适用于字段声明上下文。
答案 1 :(得分:11)
使用注释时,这是您要为类型编写完全限定名称而不是添加import语句时使用的语法。
在完全限定的条件下编写注释的正确Java语法 类型名称是将注释放在简单名称部分,例如 java.util。@ Nullable列表。但是,通常最好添加导入 java.util.List到您的源文件,以便您可以编写 @空列表。
JSR308 规范的第2页也提到了该问题,可以下载here。它说:
类型注释出现在类型的简单名称之前,例如 @NonNull字符串或java.lang。@ NonNull字符串。
答案 2 :(得分:6)
这里确实有一个奇怪的地方,就是应用以ElementType.TYPE_USE
为目标的注释不熟悉的语法。
如果您查看Nullable的文档,则会看到陌生的目标:
...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...
此注释在注释类型的简单名称之前使用,就像下面两个示例中一样:
public static <T> @Nullable Optional<T> toJavaUtil
public static <T> java.util.@Nullable Optional<T> toJavaUtil
我不知道这种目标的用途是什么,因此快速阅读后,我得到了一个简单的示例,该示例使用具有该目标的注释来选择返回类型元数据:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
boolean value() default true;
}
并使用:
public java.lang.@InterceptedReturnValue(true) String testMethod(String param) {
return null;
}
public @InterceptedReturnValue(false) String testMethod(int param) {
return null;
}
public static void main(String[] args) throws Exception {
Method m = Main.class.getDeclaredMethod("testMethod", String.class);
if(m.getAnnotatedReturnType().isAnnotationPresent(InterceptedReturnValue.class)) {
InterceptedReturnValue config = m.getAnnotatedReturnType()
.getAnnotation(InterceptedReturnValue.class);
if(config.value()) {
//logging return value enabled
}
}
}
我敢肯定,许多有用的框架(例如checkerframework)会最适当地使用ElementType.TYPE_USE