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

有人能向我解释一下 Java 内部的注释是如何工作的吗?

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

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

43319 次浏览

Here's @Override: http://www.docjar.com/html/api/java/lang/Override.java.html.

There's nothing special about it that differentiates it from an annotation you might write yourself. The interesting bits are in the consumers of the annotations. For an annotation like @Override, that would be in the Java compiler itself, or a static code analysis tool, or your IDE.

Follow this link. This will provide close answer for your problem. If we focused on annotations in Java, Annotations were introduced in Java 5 and are not Spring specific. In general, annotations allow you to add metadata to a class, method or variable. An annotation can be interpreted by the compiler (for example, the @Override annotation) or by a framework such as spring (for example, the @Component annotation).

In addition I am adding more references.

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

Basically, annotations are just markers which are read by the compiler or the application. Depending on their retention policy they are available at compile time only or are readable at runtime using reflection.

Many frameworks use runtime retention, i.e. they reflectively check whether some annotations are present on a class, method, field etc. and do something if the annotation is present (or not). Additionally, members of annotations can be used to pass further information.

The first main distinction between kinds of annotation is whether they're used at compile time and then discarded (like @Override) or placed in the compiled class file and available at runtime (like Spring's @Component). This is determined by the @Retention policy of the annotation. If you're writing your own annotation, you'd need to decide whether the annotation is helpful at runtime (for autoconfiguration, perhaps) or only at compile time (for checking or code generation).

When compiling code with annotations, the compiler sees the annotation just like it sees other modifiers on source elements, like access modifiers (public/private) or final. When it encounters an annotation, it runs an annotation processor, which is like a plug-in class that says it's interested a specific annotation. The annotation processor generally uses the Reflection API to inspect the elements being compiled and may simply run checks on them, modify them, or generate new code to be compiled. @Override is an example of the first; it uses the Reflection API to make sure it can find a match for the method signature in one of the superclasses and uses the Messager to cause a compile error if it can't.

There are a number of tutorials available on writing annotation processors; here's a useful one. Look through the methods on the Processor interface for how the compiler invokes an annotation processor; the main operation takes place in the process method, which gets called every time the compiler sees an element that has a matching annotation.

Besides what others suggested, I recommend you write a customized annotation and its processor from scratch to see how annotation works.

In my own, for example, I have written an annotation to check whether methods are overloaded in compile time.

Firstly, create an annotation named Overload. This annotation is applied to method so I annotate it with @Target(value=ElementType.METHOD)

package gearon.customAnnotation;


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


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


}

Next, create corresponding processor to handle elements annotated by defined annotation. For method annotated by @Overload, its signature must appear more than one time. Or the error is printed.

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;
}
}

After packaging annotation and its process into a jar file, create a class with @Overload and use javac.exe to compile it.

import gearon.customAnnotation.Overload;


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


@Overload
public static void foo(String s){


}


@Overload
public static void nonOverloadedMethod(){


}
}

Since nonOverloadedMethod() has not actually been overloaded, we will get the output like below:

enter image description here

Even I was looking for the answer of the same question. the below link provided the consolidated good stuff to get the inside of annotations. https://dzone.com/articles/how-annotations-work-java Hope it helps!