zoukankan      html  css  js  c++  java
  • Java API 之 Annotation功能

    JDK1.5开始增加了Annotation功能,该功能可用于:

    1、类;

    2、构造方法;

    3、成员变量;

    4、方法

    5、参数

    等的声明;

    该功能并不影响程序的运行,但是会对编译器警告等辅助工具产生影响。本文将介绍Annotation功能的使用方法。


    1、定义Annotation类型

    在定义Annotation类型时,也需要用到来定义接口的interface关键字,但需要在interface关键字前加一个@符号,即表示定义Annotation类型的关键字为@interface,这个关键字的隐含意思是继承了java.lang.annotation.Annotation接口。例如,下面的代码就定义了一个Annotation类型。

    public @interface NoMemberAnnotation{}

    上面定义的Annotation类型@NoMemberAnnotation未包含任何成员,这样的Annotation类型被称为marker annotation。下面的代码定义了一个只包含一个成员的Annotation类型。

    public @interface OneMemberAnnotatino{
        String value();
    }

    String: 成员类型。可用的成员类型有:

    1)String;

    2)Class;

    3)基本类型;

    4)枚举;

    5)Annotation;

    value:成员的名称。如果在所定义的Annotation类型中只包含一个成员,通常将成员命名为value;

    下面代码定义了一个包含多个成员的Annotation类型:

    public @interface MoreMemberAnnotation{
        String describe();
        Class type();
    }

    在为Annotation类型定义成员时,也可以为成员设置默认值。例如,下面的代码在定义Annotation类型时就为成员设置了默认值。

    public @interface DefaultValueAnnotation{
        String describe() default "<默认值>";
        Class type(0 default void.class;
    }

    在定义Annotation类型时,还可以通过Annotation类型@Target来设置Annotation类型使用的程序元素种类。如果未设置@Target,则表示适用于所有程序元素。枚举类ElementType中的枚举常量用来设置@Target,如下:

    • ANNOTATION_TYPE :表示用于Annotation类型
    • TYPE : 表示用于类、接口和枚举,以及Annotation类型
    • CONSTRUCTOR : 表示用于构造方法
    • FIELD : 表示用于成员变量和枚举常量
    • METHOD :表示用于方法
    • PARAMETER :表示用于参数
    • LOCAL_VARIABLE :表示用于局部变量
    • PACKAGE :表示用于包

    通过Annotation类型的@Retention可以设置Annotation的有效范围。枚举类RetentionPolicy中的枚举常量用于设置@Retention,如果没有设置,那么默认为CLASS常量的范围,如下所示:

    • SOURCE :表示不编译Annotation到类文件中,有效范围最小
    • CLASS :表示编译Annotation到类文件中,但是在运行时不加载Annotation到JVM中
    • RUNTIME :表示在运行时加载Annotation到JVM中,有效范围最大

    2、访问Annotation信息

    如果在定义Annotation类型时将@Retention设置为RetetionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的Annotation信息,如获取构造方法、字段和方法的Annotation信息。

    类Constructor、Field和Method继承了AccessibleObject类,而AccessibleObject类实现了AnnotatedElement,因此也就是说,Constructor、FIeld、Method均可以使用AccessibleObject实现的方法来操作注解。(注:这里Class类直接实现了AnnotatedElement不是继承AccessibleObject)

    下面,我们看看AccessibleObject继承来的方法:

    <T extends Annotation> getAnnotation(Class<T> annotationClass);

    如果该元素存在annotationClass类型的注释,则返回该注释,否则返回null;

    Annotation[] getAnnotations()

    返回该元素的所有注解

    Annotation[] getDeclaredAnnotation()

    返回直接存在于该元素的注解(例如继承而来的注解不会被返回)

    boolean isAccessible()

    该元素是否执行安全检查(安全检查如:变量设置了private属性不可以直接访问,设置为取消检查则可以反问该元素)

    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

    该元素是否存在annotationClass注解

    static void setAccessible(AccessibleObject[] array, boolean flag)

    为一组元素设置是否执行安全检查

    void setAccessible(boolean flag)

    为该元素设置是否执行安全检查


    3、DEMO

    package cn.lay.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * annotation demo
     * @ClassName: AnnotationDemo 
     * @Description: 
     * @author: lay
     * @date: Mar 18, 2018
     */
    @Test(
            value = "test", 
            ages = {23, 23, 34, 35, 34}, 
            bookEnum = BookEnum.JAVA, 
            cls = String.class,
            test2s = {@Test2(), @Test2("lay"), @Test2("zhang"), @Test2("wu")}
        )
    public class AnnotationDemo {
        public static void main(String[] args) {
            // 判断是否注解了该类型
            if (AnnotationDemo.class.isAnnotationPresent(Test.class)) {
                // 获取该注解
                Test annotation = AnnotationDemo.class.getAnnotation(Test.class);
                // 取值
                String value = annotation.value();
                // 输出
                System.out.println("value=" + value);
                int[] ages = annotation.ages();
                for (int age : ages) {
                    System.out.println("age=" + age);
                }
                BookEnum bookEnum = annotation.bookEnum();
                System.out.println("bookName=" + bookEnum.getBookName());;
                Class<?> cls = annotation.cls();
                System.out.println("class=" + cls.getName());
                Test2[] test2s = annotation.test2s();
                for (Test2 test2 : test2s) {
                    System.out.println("test2=" + test2.value());
                }
            }
        }
    }
    
    /**
     * 定义注解
     * @ClassName: Test 
     * @Description: 
     * @author: lay
     * @date: Mar 18, 2018
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test{
        String value();
        int[] ages();
        BookEnum bookEnum();
        Class<?> cls();
        Test2[] test2s();
    }
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test2{
        String value() default "lily";
    }
    
    enum BookEnum{
        
        JAVA("java"),
        SQL("sql");
        
        private String bookName;
    
        public String getBookName() {
            return bookName;
        }
    
        public void setBookName(String bookName) {
            this.bookName = bookName;
        }
    
        private BookEnum(String bookName) {
            this.bookName = bookName;
        }
    }

    控制台打印:

    value=test
    age=23
    age=23
    age=34
    age=35
    age=34
    bookName=java
    class=java.lang.String
    test2=lily
    test2=lay
    test2=zhang
    test2=wu

     更多详细内容,参阅:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

  • 相关阅读:
    SQL Server中怎样可以从SELECT语句的结果集中删除重复行
    Comparison method violates its general contract!
    如何解决 不能以 DISTINCT 方式选择 text、ntext 或 image 数据类型
    TortoiseSVN—Repo-browser
    使用BigDecimal完成小数点后的精确位数的四舍五入
    CREATE TABLE 语句后的 ON [PRIMARY] 起什么作用
    sql server 获取每一个类别中值最大的一条数据
    C# 正则表达式
    Linq to XML 读取XML 备忘笔记
    安装双系统需要注意的几个问题
  • 原文地址:https://www.cnblogs.com/lay2017/p/8598386.html
Copyright © 2011-2022 走看看