Java注解提供关于代码的信息,并且对它们注解的代码没有直接的影响。在这篇教程中,我们将学习Java注解,如何自定义注解,注解用法和如何使用反射解析注解。
Java注解在Java1.5被引用并且在一些Java框架如Hibernate,Jersey,Spring中被广泛使用。注解是被嵌入到程序自身中的程序的元数据。它可以被注解解析工具或编译器解析。我们也可以指定注解的生命周期,或者仅在编译期间可用或者直到运行时。
在引入注解之前,我们可以通过程序注释或者Java文档来获取程序的元数据,但是注解提供的更多。它不仅包含元数据而且它能决定自身是否可用而且注解解析器可以使用它来控制处理流。
在Java中创建自定义注解
创建自定义注解类似于写一个接口,除了注解的接口关键字前多了一个@符号。我们可以在注解中声明方法。让我们看一个注解的例子然后再讨论它的特性。
package com.journaldev.annotations; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target(ElementType.METHOD) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface MethodInfo{ String author() default 'Pankaj'; String date(); int revision() default 1; String comments(); }
注解方法不能有参数。
注解方法的返回值类型限于基本类型,String,Enums,Annotation或者上面这些的组合。
注解方法可以有默认值。
注解可以附加元数据。元注解可以提供关于这个注解的信息。
四种元注解:
[email protected] that elements using this annotation should be documented by javadoc and similar tools. This type should be used to annotate the declarations of types whose annotations affect the use of annotated
elements by their clients. If a type declaration is annotated with Documented, its annotations become part of the public API of the annotated elements.
[email protected] – indicates the kinds of program element to which an annotation type is applicable. Some possible values are TYPE, METHOD, CONSTRUCTOR, FIELD etc. If Target meta-annotation is not present, then annotation can
be used on any program element.
[email protected] – indicates that an annotation type is automatically inherited. If user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class’s superclass
will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached.
[email protected] – indicates how long annotations with the annotated type are to be retained. It takes RetentionPolicy argument whose Possible values are SOURCE, CLASS and RUNTIME
Java内置注解
Java提供三个内置注解:
[email protected]当我们要重写父类的一个方法时,我们应该使用这个注解告诉编译器我们重写了这个方法。因此当父类的这个方法被移除或发生改变时,编译器将报错。
[email protected]当我们想让编译器知道一个方法已经过时时,我们应该这个注解。Java推荐将这个方法过时的原因以及它的替代方案写在Java文档中。
[email protected]这个仅是用来告诉编译器忽略产生的特定警告,比如在泛型中使用原始类型。它的retention策略是SOURCE,所以它将被编译器丢弃。
让我们看一个使用Java内置注解和我们上面自定义的那个注解的一个例子:
package com.journaldev.annotations; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; public class AnnotationExample { public static void main(String[] args) { } @Override @MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 1) public String toString() { return 'Overriden toString method'; } @Deprecated @MethodInfo(comments = 'deprecated method', date = 'Nov 17 2012') public static void oldMethod() { System.out.println('old method, don't use it.'); } @SuppressWarnings({ 'unchecked', 'deprecation' }) @MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 10) public static void genericsTest() throws FileNotFoundException { List l = new ArrayList(); l.add('abc'); oldMethod(); } }
我相信这个例子大家都能够看的懂,它向我们展示了在不同情境下注解的使用。
Java注解解析
我们将使用反射从一个类中解析主解。请注意注解的Retention策略必须是RUNTIME,否则在运行时它的信息将失效,我们将得不到任何信息。
package com.journaldev.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class AnnotationParsing { public static void main(String[] args) { try { for (Method method : AnnotationParsing.class .getClassLoader() .loadClass(('com.journaldev.annotations.AnnotationExample')) .getMethods()) { // checks if MethodInfo annotation is present for the method if (method .isAnnotationPresent(com.journaldev.annotations.MethodInfo.class)) { try { // iterates all the annotations available in the method for (Annotation anno : method.getDeclaredAnnotations()) { System.out.println('Annotation in Method '' + method + '' : ' + anno); } MethodInfo methodAnno = method .getAnnotation(MethodInfo.class); if (methodAnno.revision() == 1) { System.out.println('Method with revision no 1 = ' + method); } } catch (Throwable ex) { ex.printStackTrace(); } } } } catch (SecurityException | ClassNotFoundException e) { e.printStackTrace(); } } }
上面程序的输出为:
Annotation in Method 'public java.lang.String com.journaldev.annotations.AnnotationExample.toString()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=Main method, date=Nov 17 2012) Method with revision no 1 = public java.lang.String com.journaldev.annotations.AnnotationExample.toString() Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @java.lang.Deprecated() Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=deprecated method, date=Nov 17 2012) Method with revision no 1 = public static void com.journaldev.annotations.AnnotationExample.oldMethod() Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.genericsTest() throws java.io.FileNotFoundException' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=10, comments=Main method, date=Nov 17 2012)