zoukankan      html  css  js  c++  java
  • Annotation

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

      系统内建的Annotation:

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

      1.@Override,相信大家对这个比较熟悉,如果我们要重写一个类的方法的时候,要加上这个注解,但是很多人会反问,不加也是没问题的,但是我们必须考虑到的是程序的正确性,如果你本身的意图是重写这个方法,但是你在写的时候把方法名写错了,那么这就不是重写了,也改变了意图,所以在重写的方法上加上这个注解是防患于未然,也是明确的告诉别人我这个方法是重写的,如何我写错方法名,那么这个注解也会提醒我。

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

     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可以压制的警告。

      警告集:

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

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

     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 }
  • 相关阅读:
    oracle语法查某个字段为空
    MQC集群配置错误
    maven打包报错:Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.5:test
    ibm-mq-scope属性的作用?
    Name jms can't bind to context问题解决
    对比两张Excel表数据差异时,遇到数据雷响不一致
    excel如何复制筛选内容
    怎么对比两个excel文档的数据差异
    怎么把txt转换成excel
    一张表的某列值去更新另一张表的某列值。
  • 原文地址:https://www.cnblogs.com/Ray-xujianguo/p/3330057.html
Copyright © 2011-2022 走看看