zoukankan      html  css  js  c++  java
  • Annotation

    Annotation究竟是什么?

    Annotation 提供了一条与程序元素关联任何信息或者任何元数据(metadata)的途径。从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation的“name=value”结构对中。 annotation类型是一种接口,能够通过java反射API的方式提供对其信息的访问。

    annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息。需要注意的是,这里存在着一个基本的潜规则:annotaion不能影响程序代码的执行,无论增加、删除 annotation,代码都始终如一的执行。另外,尽管一些annotation通过java的反射api方法在运行时被访问,而java语言解释器在工作时忽略了这些annotation。正是由于java虚拟机忽略了annotation,导致了annotation类型在代码中是“不起作用”的;只有通过某种配套的工具才会对annotation类型中的信息进行访问和处理。本文中将涵盖标准的annotation和meta- annotation类型,陪伴这些annotation类型的工具是java编译器(当然要以某种特殊的方式处理它们)

    1、基本注释

      @Override:表明该方法是重写父类的方法,eg:

    class Test
    {
    @Override
    public void func()
    {
    ......
    }
    }
      @Deprecated:表示该类或方法已过时,程序使用这些类或方法时会发出编译警告。

      @SuppressWarnings:指示类或方法取消显示的编译警告,@SuppressWarnings中只有一个类型为String[]的元素成员value,其中常见的参数值为:

               1.deprecation:使用了不赞成使用的类或方法时的警告;
       2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 
       3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
       4.path:在类路径、源文件路径等中有不存在的路径时的警告; 
       5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 
       6.finally:任何 finally 子句不能正常完成时的警告; 
       7.all:关于以上所有情况的警告。

      使用示例:

    @SuppressWarnings(value="unchecked")
    public void func1()
    {
    List list = new ArrayList<Integer>();
    list.add(10); //list没有指定泛型,此处会产生警告

    List<String> ls = list; //将不带泛型的对象赋给带泛型的对象,产生警告,导致“堆污染”
    System.out.println(ls.get(0));//该语句运行时产生异常
    }
    @SuppressWarnings({"unchecked", "deprecation"})
    public void func2()
    {

    }
       @SafeVarargs:指示取消显示个数可变形参产生的警告,eg:

    @SafeVarargs
    public static void func3(List<String>...aryStringList) //个数可变的形参相当于是数组,因为没有泛型数组,所以形参相当于是一个List[],泛型被抹去,产生“堆污染”
    {

    }
      @FunctionalInterface:指示该接口是一个函数式接口(只有一个抽象方法,可以包含多个默认方法或静态方法的接口)。

    2、自定义注释

     使用@interface来自定义一个注解,如下定义了名为Coder的注解,注解中包含两个元素personId(int类型)和company(String类型,默认值为"peking"):

    public @interface Coder
    {
    int personId();
    String city()default "peking";
    }
      如果注释中仅包含一个元素,这个元素的名字应该为value,如:

    public @interface Coder
    {
    String value();
    }
      注释中可以包含枚举类型:

    public @interface FruitColor
    {
    public enum Color{ BULE,RED,GREEN}; //枚举
    Color CoderColor() default Color.GREEN;
    }
      声明(使用)自定义的注释的时候需要为其成员变量指定值,如果该变量无默认值的话:

    @Coder(personId = 1001)
    public void func()
    {
    ......
    }
      如果注释中元素的名字为value,那么在使用这个注解的时候,元素的名字和等号都可以省略,例如:

    @Coder(“value”)
    public void func()
    {
    ......
    }
      根据注解是否包含成员可以将注解分为标记注解(如@Override)和元注解(如@Retention)。

    3、JDK的元注释

      在java.lang.annotation下有6个元Annotation,其中@Repeatable用于定义重复注解,其余5个用来修饰自定义的注解。

      @Retention:指定被修饰的Annotation保留的时间,通过指定其value成员变量的值:

    //编译器把注释保存在class文件中,当运行java程序时,JVM不可获取注释信息,这是默认值。
    @Retention(value = RetentionPolicy.CLASS)
    @interface Testable{}

    //编译器把注释保存在class文件中,当运行java程序时,JVM可以获取注释信息
    //程序可以通过反射获取该注释
    @Retention(value = RetentionPolicy.RUNTIME)
    @interface Testable{}

    //注释保存在源码中,编译器直接丢弃该注释。
    @Retention(value = RetentionPolicy.SOURCE)
    @interface Testable{}
      @Target:指定被修饰的Annotation能够修饰哪些程序单元,其成员value值常见的值有:

        ElementType.TYPE为指定该Annotation可以修饰类、接口(包括注解)、枚举定义。
        ElementType.CONSTRUCTOR为指定该Annotation只能修饰构造方法。
        ElementType.METHOD为指定该Annotation只能修饰方法定义。
        ElementType.FIELD为指定该Annotation只能修饰成员变量。

      @Documented:指定被修饰的Annotation将被javadoc工具提取成文档。

      @Inherited:指定被修饰的Annotation具有继承性,使用该Annotation的类的子类自动继承该Annotation。

      @Repeatable:在java 8之前,程序的元素(类、方法等)不能添加相同类型的注解,比如下面为使用两个@Result注解的实现方法:

    @Results({@Result(name = "liyang"), @Result(name = "wulei")})
    public void func()
    {

    }
        java 8中允许使用多个相同类型的注解,通过为注解添加@Repeatable修饰。

    4、使用自定义的注解

      可以为类中某些方法实现注解,然后其他程序通过使用实现反射功能的API来读取该注解,通过该注解或注解中的成员来做对应的一些处理:

    //Foo.java

    package xu;

    import java.lang.annotation.*;

    @Retention(value = RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @interface Testable
    {
    int id();
    String city();
    }

    public class Foo
    {
    public static void main (String[] args)throws Exception
    {

    }
    @Testable(id = 1001, city = "peking")
    public static void func()
    {
    System.out.println("func called");
    }
    }
    //Test.java

    package xu;

    import java.lang.annotation.*;
    import java.lang.reflect.Method;

    public class Test
    {
    public static void main (String[] args)throws Exception
    {
    //Class<?> cls = Class.forName("xu.Foo"); //获取类的class对象
    //getMethod()获得类中指定方法,getMethods()获得类中所有方法。
    for(Method m : Class.forName("xu.Foo").getMethods())
    {
    if(m.isAnnotationPresent(Testable.class)) //如果该方法使用了Testable注解
    {
    m.invoke(null); //调用该方法
    }
    }

    //getAnnotation获得指定注解,getAnnotations获得所有注解
    Annotation[] ary1 = Class.forName("xu.Foo").getMethod("func").getAnnotations();
    for(Annotation tag : ary1)//输出Test类中func方法的所有注解
    {
    System.out.println(tag);
    }

    //Foo tt = (Foo)cls.getDeclaredConstructor().newInstance(); //获取Foo类的实例
    Foo tt = new Foo();
    Annotation[] ary2 = tt.getClass().getMethod("func").getAnnotations();
    for(Annotation tag : ary1)//获取tt对象的func方法的所有注解的元数据
    {
    if(tag instanceof Testable)
    {
    int id = ((Testable)tag).id();
    String city = ((Testable)tag).city();
    System.out.println(city + id);
    }
    }
    }
    }

    /*
    */


    5、类型注解

      java 8中对@Target的成员value的值增加了ElementType.TYPE_USE,它被称作类型注解,指定被修饰的注解除了在定义程序元素(类、接口、方法、成员变量)时使用,还可以在任何用到类型的地方使用,如使用new创建对象、类型转换、使用implements实现接口、使用throws声明抛出异常的时候:

    @Target(ElementType.TYPE_USE)
    @interface notNull{}

    @notNull
    class Type implements @notNull Serializable
    {
    public void func1()//throws @notNull FileNotFoundException
    {
    Object obj = "fkjava.org";
    String str = (@NotNull String)obj;
    Object win = new @NotNull JFrame("test");
    }
    public void func2(List<@NotNull String> info){}
    }

  • 相关阅读:
    协程—gevent模块的使用
    协程—概念以及基本使用
    Python—同步和互斥
    Hugo博客搭建
    Linux编辑利器-Vim
    Linux命令与Shell
    python入门基础
    .netcore程序在linux下用supervisor守护
    .netcore中添加Swagger
    winform或wpf中全局异常捕获
  • 原文地址:https://www.cnblogs.com/djh222/p/10551009.html
Copyright © 2011-2022 走看看