像@Override这样的注释如何在Java内部工作?

2022-08-31 10:13:16

任何人都可以向我解释注释如何在Java内部工作吗?

我知道我们如何通过在java中使用java.lang.annotation库来创建自定义注释。但我仍然不明白它在内部是如何工作的,例如,@Override注释。

如果有人能详细解释这一点,我将非常感激。


答案 1

各种注释之间的第一个主要区别是它们是在编译时使用,然后被丢弃(如)还是放置在已编译的类文件中并在运行时可用(如Spring的)。这由注释的@Retention策略确定。如果您正在编写自己的注释,则需要确定注释是在运行时(也许用于自动配置)还是仅在编译时(用于检查或代码生成)有用。@Override@Component

使用批注编译代码时,编译器看到的注释就像它看到源元素上的其他修饰符一样,如访问修饰符 (/) 或 .当它遇到注释时,它会运行一个注释处理器,这就像一个插件类,它说它对特定注释感兴趣。注释处理器通常使用反射 API 来检查正在编译的元素,并且可能只是对它们运行检查、修改它们或生成要编译的新代码。 是第一个示例;它使用反射 API 来确保它可以在其中一个超类中找到方法签名的匹配项,如果不能,则使用 它来导致编译错误。publicprivatefinal@OverrideMessager

有许多关于编写注释处理器的教程;这是一个有用的。查看处理器接口上的方法,了解编译器如何调用注释处理器;main 操作在方法中发生,每次编译器看到具有匹配注释的元素时,都会调用该方法。process


答案 2

除了其他人的建议之外,我建议您从头开始编写自定义注释及其处理器,以查看注释的工作原理。

例如,在我自己的注释中,我写了一个注释来检查方法在编译时是否重载。

首先,创建一个名为 的注释。此注释应用于方法,因此我用Overload@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

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

@Target(value=ElementType.METHOD)
public @interface Overload {

}

接下来,创建相应的处理器来处理由定义的注释注释的元素。对于 注释的方法,其签名必须出现多次。或者打印错误。@Overload

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

将注释及其过程打包到 jar 文件中后,使用并使用 javac.exe 创建一个类来编译它。@Overload

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

由于实际上尚未过载,我们将得到如下输出:nonOverloadedMethod()

enter image description here


推荐