在 Java 限定类型内部使用注解 tmesis 的目的是什么?

2022-09-04 02:34:59

这有目的吗?static @NotNull @Other My.@NotNull @Other Builder createBuilder()

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

public class A {
    static class My {
        static class Builder {
            public My build() {
                return new My(); } } }

    @Target({ElementType.METHOD, ElementType.TYPE_USE})
    public @interface NotNull { }

    @Target({ElementType.METHOD, ElementType.TYPE_USE})
    public @interface Other { }

    public static @NotNull @Other My.@NotNull @Other Builder createBuilder() {
        return new My.Builder();
    }
}

答案 1

使用这种结构的主要原因是向后兼容性。

在Java 8之前,没有类型注释,因此方法注释通常用于实际描述方法的返回类型,例如

@Target(ElementType.METHOD)
public @interface NotNull { }

@Target(ElementType.METHOD)
public @interface Other { }

public static @NotNull @Other My.Builder createBuilder() {
    return new My.Builder();
}

从 Java 8 开始,您可以对返回类型本身进行注释,这就是您通常要执行的操作。但是,要支持仍在查找方法注释的旧工具,可以保留 .对于由简单名称组成的返回类型,方法注释和返回类型注释的代码位置是相同的,因此您可以同时创建方法注释和返回类型注释,只需一次出现,即@TargetMETHOD

@MethodAndTypeAnnotation ReturnType method() …

但是,对于限定名称,语法是不同的,因为类型注释必须紧挨着注释元素的简单名称之前,即

@Target(ElementType.TYPE_USE)
public @interface NotNull { }

@Target(ElementType.TYPE_USE)
public @interface Other { }

public static My.@NotNull @Other Builder createBuilder() {
    return new My.Builder();
}

对于纯类型注释,使用会导致编译器错误,因为它将尝试注释,它在这里仅用作限定符,而不是实际的类型使用。请注意,如果 是内部类而不是嵌套类(即不是),则注释外部类型是合法的,尽管不太可能是必需的。public static @NotNull @Other My.Builder createBuilder()MyBuilderstatic

所以在你的情况下

@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface NotNull { }

@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface Other { }

//            method annotation    type annotation
public static @NotNull @Other   My.@NotNull @Other Builder createBuilder() {
    return new My.Builder();
}

这两个匹配项都需要对方法和返回类型进行批注。如前所述,如果 是一个内部类,则第一次出现对外部类型进行注释是合法的,并且无论您是否愿意,它都会对其进行注释。Builder

因此,通常不建议将“类型使用”注释范围与其他范围混合使用,而是更新仍需要方法或字段注释的任务的代码处理工具,这些任务实际上是类型注释的工作。


如前所述,对于简单名称,您可以一次对方法进行批注并返回类型,这在使用语句时也适用于嵌套类型。但这需要顶级类位于包中:import

package example;

import example.A.My.Builder;

public class A {
    static class My {
        static class Builder {
            public My build() {
                return new My(); } } }

    @Target({ElementType.METHOD, ElementType.TYPE_USE})
    public @interface NotNull { }

    @Target({ElementType.METHOD, ElementType.TYPE_USE})
    public @interface Other { }

    public static @NotNull @Other Builder createBuilder() {
        return new My.Builder();
    }
}

答案 2

推荐