Annotation

  从JDK1.5开始,Java就增长了Annotation这个新的功能,这种特性被称为元数据特性,同时也被称为注释。html

  系统内建的Annotation:java

  提醒:如下这三个系统内建的Annotation位于java.lang包下linux

  1.@Override,相信你们对这个比较熟悉,若是咱们要重写一个类的方法的时候,要加上这个注解,可是不少人会反问,不加也是没问题的,可是咱们必须考虑到的是程序的正确性,若是你自己的意图是重写这个方法,可是你在写的时候把方法名写错了,那么这就不是重写了,也改变了意图,因此在重写的方法上加上这个注解是防患于未然,也是明确的告诉别人我这个方法是重写的,如何我写错方法名,那么这个注解也会提醒我。数组

  2.@Deprecated,表示这个程序元素很危险或者存在更好的选择,不鼓励采用这种元素。ide

 

 1 @Deprecated
 2 public class DeprecatedDemo {
 3 
 4     @Deprecated
 5     public static final String name = "xujianguo";
 6     
 7     @Deprecated
 8     public void print() {
 9         System.out.println("This is the deprecated method");
10     }
11 }

  上面这个类说明了@Deprecated注解也是用在类上,成员属性上,还有方法上,这个类用起来不会报错,但会有警告的信息,表示你所用的东西已通过时了。工具

  3.@SuppressWarnings,表示取消显示指定的编译器警告,经过这个注解咱们能够取消一个没必要要的警告,如泛型警告和过期警告,经过查看API文档咱们能够发现,该Annotation下有一个value的属性,返回值一个String类型的数组,具体为:public abstract String[] value,这个属性实际上是一个警告集,里面用放的是@SuppressWarnings能够压制的警告。spa

  警告集:code

关键字 关键字
deprecation 使用了不同意使用的类或者方法的警告
unchecked 执行了未检查的转换警告,如泛型操做中没有指定泛型
fallthrough 当switch程序块执行到下种状况时没有break语句的警告
path 在类路径、源文件路径等中有着不存在路径时的警告
serial 当在可序列化类上缺乏serialVersionUID定义时的警告
finally 任何finally子句不能完成时的警告
all 关于以上全部的警告

  下面演示一个压制deprecatation和unchecked警告的Demo:htm

 

 1 /**
 2  * 该类实现了序列化接口,若无serialVersionUID会出现警告
 3  * @author Guo
 4  */
 5 @SuppressWarnings({"serial", "unchecked"})
 6 public class SuppressWarningsDemo implements Serializable{
 7     
 8     public static void main(String[] args) {
 9         
10         /**
11          * 没有指定泛型,出现警告
12          * @author Guo
13          */
14         List<String> list = new ArrayList();
15     }
16 }

 

  自定义Annotation:对象

  定义本身的Annotation很是简单,就像定义一个接口那样:

1 [public] @interface MyAnnotation {
2 
3 }

  格式很简单,一个Annotation可能接收各类参数,就像SuppressWarnings注解那样,里面能够接收一个数组,下面咱们介绍一个它参数定义:

  1.基本变量,能够是String类型的,也能够是int类型的,格式:public 类型 变量名();

  2.数组类型,数组的定义格式也是大同小异:public 类型[] 变量名();

  3.枚举类型,经过定义枚举类型,就能够限定注解里面的内容,格式:格式:public enum 变量名();

  4.默认值,在Annotation中写好默认值,在别的类上使用注解的时候就能够不用写值了,格式:public 类型 变量名() default 默认值;

  下面简单演示一下,你们加深一下印象:

 1 enum MyEnum {
 2     xp, win7, linux;
 3 }
 4 
 5 public @interface MyAnnotation {
 6 
 7     public String name() default "xujianguo";
 8     public int age() default 20;
 9     public String[] array();
10     public MyEnum system() default MyEnum.linux;
11 }
12 
13 class Test {
14 
15     @MyAnnotation(name="zyp", age=20, array = {"zhou", "yan", "ping"}, system=MyEnum.win7)
16     public static void main(String[] args) {
17         System.out.println("Just Test");
18     }
19 }

  如今咱们要讨论一个问题,你自定义好的就能在JVM跑吗,其实你看看API中系统内建的三个Annotation,它们都使用了一个注解@Retention,这个注解位于java.lang.annotation包下,其实这个包下还有几个Annotation,咱们也介绍一个,不太重点的是@Retention:

  1.@Documented,指示某一类型的注释将经过 javadoc 和相似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。若是类型声明是用Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。简单的说就是用了这个注解,你之后用该Annotation的时候在上面加上注释会被记录到文档上。

  2.@Inherited,指示注释类型被自动继承。若是在注释类型声明中存在 Inherited元注释,而且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层(Object) 为止。若是没有超类具备该类型的注释,则查询将指示当前类没有这样的注释。简单的说就是这个注解至关于extends啊,父类若是有了某个注解,那个这个注解在子类中也是拥有的,经过反射也能够拿到注解上的信息。

  3.@Target,指示注释类型所适用的程序元素的种类。若是注释类型声明中不存在 Target 元注释,则声明的类型能够用在任一程序元素上。若是存在这样的元注释,则编译器强制实施指定的使用限制。简单的说这个注解就是限制咱们的Annotation能够用在什么地方,它有个value属性,是ElementType类型的,ElementType中规定如下几种范围:

范围

描述

ANNOTATION_TYPE

只能用在注释声明上

CONSTRUCTOR

只能用在构造方法上

FIELD

只能用在字段的声明上

LOCAL_VARIABLE

只能用在局部变量的声明上

METHOD

只能用在方法的声明上

PACKAGE

只能用在包的声明上

PARAMETER

只能用在参数的声明上

TYPE

只能用在类、接口、枚举类型上

  提醒:其实这些限制的范围是能够叠加的,例如,你的Annotation想在类或者方法上使用,能够这么写:@Target(ElementType.TYPE, ElementType.METHOD)

  4.@Retention,指示注释类型的注释要保留多久。这个注释有个value的属性,属性的类型为RetentionPolicy,而RetentionPolicy里面有三个常变量,咱们一块儿来看看这三个常变量。

范围 描述
SOURCE 此Annotation的信息只会保存在程序源文件中(java文件),不会保留在编译好的文件中(class文件)
CLASS

此Annotation的信息保留在程序源文件(java文件)和编译好的文件中(class文件),使用此类的时候

Annotation的信息不会被加载到JVM中,若是一个Annotation没有声明使用什么范围,这个就是默认范围。

RUNTIME 此Annotation的信息会保留在源文件、类文件中,还会被加载到JVM中

  很明确的看出RUNTIME才是咱们想要的菜,由于咱们要利用Annotation去获取一些信息,咱们也来看看咱们系统内建的Annotation会属于哪些呢?@Override采用的是Retention(value=RetentionPolicy.SOURCE),@Deprecated采用的是Retention(value=RetentionPolicy.RUNTIME),@SuppressWarnings采用的也是Retention(value=RetentionPolicy.SOURCE),总结一下,一个能真正对咱们来讲起做用的Annotation应该这样定义:

1 @Retention(value=RetentionPolicy.RUNTIME)
2 public @interface MyAnnotation {
3 
4     public String name() default "xujianguo";
5     public int age() default 20;
6     public String[] array();
7     public MyEnum system() default MyEnum.linux;
8 }

   

  Annotation与反射

  说到Annotation的应用,则不会离开反射,在Class类中存在如下几种跟Annotation操做相关的方法:

方法 描述
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 若是存在该元素的指定类型的注释,则返回这些注释,不然返回 null

public Annotation[] getAnnotations()

返回此元素上存在的全部注释
public Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的全部注释。
public boolean isAnnotation() 判断元素是否表示一个注释
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 若是指定类型的注释存在于此元素上,则返回 true,不然返回 false

   下面我自定义一个Annotation,用这个Annotation来模仿JUnit的@Test注解,同时自定义的这个Annotation也有属性,要将这个属性的值拿出来:

  自定义的Annotation-TestSimulation:

1 @Retention(value=RetentionPolicy.RUNTIME)
2 public @interface TestSimulation {
3     public String author() default "xujianguo";
4 }

  运用注解的类AnnotationDemo类:

 1 public class AnnotationDemo {
 2 
 3     @TestSimulation(author="zhouyanping")
 4     public void print() {
 5         System.out.println("This is the method of print");
 6     }
 7     
 8     public void say() {
 9         System.out.println("This is the method of say");
10     }
11     
12     @TestSimulation
13     public void coding() {
14         System.out.println("This is the method of coding");
15     }
16 }

  进行反射解析的AnnotationUtil类:

 1 public class AnnotationUtil {
 2 
 3     public static void main(String[] args) throws Exception {
 4         
 5         /**
 6          * 反射类的对象和拿出一个方法组
 7          * @author Guo
 8          */
 9         Class clazz = Class.forName("com.xujianguo.test.AnnotationDemo");
10         Object object = clazz.newInstance();
11         Method[] methods = clazz.getMethods();
12         
13         for(Method method : methods) {
14             
15             /**
16              * 对方法上的注解进行核对
17              * @author Guo
18              */
19             if(method.isAnnotationPresent(TestSimulation.class)) {
20                 
21                 /**
22                  * 拿到指定的Annotation并获取相应的信息
23                  * @author Guo
24                  */
25                 TestSimulation ts = method.getAnnotation(TestSimulation.class);
26                 System.out.println(ts.author());
27                 method.invoke(object);
28             }
29         }
30     }
31 }
相关文章
相关标签/搜索