任何人都可以向我解释注解在 Java 内部是如何工作的吗?
我知道我们如何通过在 java 中使用 java.lang.annotation 库来创建自定义注释。但我仍然不明白它是如何在内部工作的,例如 @Override 注释。
如果有人能详细解释一下,我将非常感激。
任何人都可以向我解释注解在 Java 内部是如何工作的吗?
我知道我们如何通过在 java 中使用 java.lang.annotation 库来创建自定义注释。但我仍然不明白它是如何在内部工作的,例如 @Override 注释。
如果有人能详细解释一下,我将非常感激。
注释类型之间的第一个主要区别是它们是在编译时使用然后被丢弃(如@Override
)还是放置在编译的类文件中并在运行时可用(如 Spring 的@Component
)。这是由注解的@Retention策略决定的。如果您正在编写自己的注释,则需要确定该注释是在运行时有用(可能用于自动配置)还是仅在编译时有用(用于检查或代码生成)。
使用注解编译代码时,编译器看到注解就像看到源元素上的其他修饰符一样,例如访问修饰符 ( public
/ private
) 或final
. 当它遇到一个注解时,它会运行一个注解处理器,它就像一个插件类,它表示它对特定的注解感兴趣。注释处理器通常使用反射 API 来检查正在编译的元素,并且可以简单地对它们运行检查、修改它们或生成要编译的新代码。@Override
是第一个例子;它使用反射 API 来确保它可以在其中一个超类中找到方法签名的匹配项,Messager
如果不能,则使用 导致编译错误。
有许多关于编写注释处理器的教程;这是一个有用的。查看接口上的Processor
方法,了解编译器如何调用注释处理器;主要操作发生在process
方法中,每次编译器看到具有匹配注释的元素时都会调用该方法。
除了其他人的建议之外,我建议您从头开始编写自定义注释及其处理器,以了解注释的工作原理。
例如,我自己写了一个注解来检查方法是否在编译时重载。
首先,创建一个名为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
并使用javac.exe进行编译。
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()
实际上并没有被重载,我们将得到如下输出:
这是@Override
: http: //www.docjar.com/html/api/java/lang/Override.java.html。
它与您可能自己编写的注释没有什么特别之处。有趣的是注释的消费者。对于像这样的注解@Override
,它可能在 Java 编译器本身、静态代码分析工具或您的 IDE 中。
基本上,注释只是编译器或应用程序读取的标记。根据它们的保留策略,它们仅在编译时可用,或者在运行时使用反射可读。
许多框架使用运行时保留,即它们反射性地检查类、方法、字段等上是否存在某些注释,并在注释存在(或不存在)时执行某些操作。此外,注释的成员可用于传递更多信息。
按照这个链接。这将为您的问题提供密切的答案。如果我们关注 中的注解Java
,注解是在 Java 5 中引入的,并不是 Spring 特有的。通常,注释允许您将元数据添加到类、方法或变量中。注解可以由编译器(例如@Override注解)或诸如spring之类的框架(例如@Component注解)来解释。
此外,我正在添加更多参考。
甚至我也在寻找同一个问题的答案。下面的链接提供了综合的好东西来获取注释的内部。https://dzone.com/articles/how-annotations-work-java 希望对您有所帮助!