ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

“内部工作”是什么意思?编译器?运行时?
@chrylis Work 内部意味着如何自动识别此方法是覆盖方法或此方法不是覆盖方法。这两个时间都在工作。就像在编译时覆盖注释工作和弹簧控制器注释在运行时工作

c
chrylis -cautiouslyoptimistic-

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

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

有许多关于编写注释处理器的教程; here's a useful one。查看 the Processor interface 上的方法,了解编译器如何调用注释处理器;主要操作发生在 process 方法中,每次编译器看到具有匹配注释的元素时都会调用该方法。


很高兴向我们指出 Spring 的注解处理器是如何解析 @Component 并将类注入到其容器中的
@shanyangqu 这不是问题的主题,不是特定于春季的。您可以自己阅读后处理器类。
E
Eugene

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

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

首先,创建一个名为 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文件后,用@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() 实际上并没有被重载,我们将得到如下输出:

https://i.stack.imgur.com/fZ1W3.png


以上信息非常尊重JDK6(为此+1),但是如何使用JDK5来实现同样的事情呢?使用 JDK6 SupportedAnnotationTypes,AbstractProcessor 类变得更简单,但过去如何发生同样的事情(如 jdk5 上的 Spring FrameWork 2.5)?JVM 如何检测 jdk5 中的类注释处理器?您能否通过编辑 2 部分中的答案来指导(一个用于 JDK5,当前版本用于 Jdk6+)?
在您的班级 OverloadProcessor::process 为什么是 entry.getValue() == 1?不必在父类/接口上添加注释,所以 roundEnv.getElementsAnnotatedWith(Overload.class) 不会得到父类/接口,对吧?
我对此部分感到困惑,但我认为您的回答非常有帮助。
@s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ 如果将方法视为重载,则至少应在类中定义另一个同名的方法。
@Raining 让一个方法说 Overloaded,它必须在同一个类中出现多次,但如果它是 `== 1`,那么它是一个错误。
M
Matt Ball

这是@Overridehttp://www.docjar.com/html/api/java/lang/Override.java.html

它与您可能自己编写的注释没有什么特别之处。有趣的位在注释的 consumers 中。对于像 @Override 这样的注解,它可能在 Java 编译器本身、静态代码分析工具或您的 IDE 中。


我知道 Override 注释的源代码。但它是如何在内部工作的。像如何识别这个方法不是覆盖方法或者这个是覆盖方法?或者我可以创建我的自定义覆盖注释吗?它应该与 java override annotation 完全相同的行为
正如我在回答中所说,行为不是注释的一部分。解释在于使用注释的事物。因此,除非您更改使用者,否则您实际上无法创建自己的自定义版本的 @Override(或其他标准注释)。
T
Thomas

基本上,注释只是编译器或应用程序读取的标记。根据它们的保留策略,它们仅在编译时可用,或者在运行时使用反射可读。

许多框架使用运行时保留,即它们反射性地检查类、方法、字段等上是否存在某些注释,并在注释存在(或不存在)时执行某些操作。此外,注释的成员可用于传递更多信息。


R
Ruchira Gayan Ranaweera

遵循此link。这将为您的问题提供密切的答案。如果我们专注于 Java 中的注解,注解是在 Java 5 中引入的,并不是 Spring 特定的。通常,注释允许您将元数据添加到类、方法或变量中。注解可以由编译器(例如@Override注解)或诸如spring之类的框架(例如@Component注解)来解释。

此外,我正在添加更多参考。

http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html http://www.coderanch.com/how-to/java/AnnotationsExample


@LuiggiMendoza java 1.7 注释文档添加
@Ruchira 我打开了所有链接,但我仍然不清楚它是如何工作的。你能详细解释一下我,比如考虑弹簧注释吗?我可以通过使用注释来完成所有事情,而无需在 spring.xml 文件中编写任何配置。它是否在内部将注释绑定到 xml 配置?
@ChiragDasani 看看这个。这可能会对您有所帮助static.springsource.org/spring/docs/3.0.0.M3/reference/html/…,还可以查看此 SO 帖子 stackoverflow.com/questions/2798181/…
K
Kusum

甚至我也在寻找同一个问题的答案。下面的链接提供了综合的好东西来获取注释的内部。 https://dzone.com/articles/how-annotations-work-java 希望对您有所帮助!