注解(Annotation)

前言

使用JAVA语言,就少不了提到注解。不管是看JDK中源码还是自己开发项目,都会用的。注解是java5引入的概念,那么先来详细的了解下什么是注解,有什么分类。怎么用?

参考资料

https://www.cnblogs.com/xdp-gacl/p/3622275.html

什么是注解

注解可以看做一种元数据,即一种描述数据的数据。注解本身是描述其他数据的。在jav中,注解就是源代码的元数据。比如,下面这段代码:
@Override
public String toString() {
return “This is String Representation of current object.”;
}
其中的Override就是一个重写的注解。注解在一个方法上,含义是告诉编译器在编译时候对此方法进行编译检查。如参数或者函数名称错误,可以提示编译错误,避免在运行时候才发现。

标准定义:
Annotation是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符。它是一种由JSR-175标准选择用来描述元数据的一种工具。

注解分类

注解分元注解和自定义注解。

1. 元注解
元注解是一个特殊的注解,特殊在于可以注解到其他注解上。
元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
@Retention
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
    如以下代码::
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
    }
    TestAnnotation 可以在运行时候访问到。
    如上3中注解的保留期不一样,访问方式也不一样,后面注解的获取中会讲到怎么获取有注解的类或者方法。

@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。暂时放过。

@Target
Target 是目标的意思,@Target 指定了注解运用的地方。限定了运用的场景。
如注解可以应用于方法上、类上、方法参数上等等。取值如下:

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。注解的值可以同时取多个可以使用。暂时放过。

注解定义

注解通过 @interface 关键字进行定义的一个类。如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

int id();

String msg();

}

注解属性

注解的属性即注解类的成员属性,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
如上定义的id、msg

注解使用

定义好了注解类,怎么使用到目标代码上呢?使用时候如下,@加注解类到目标代码上。

@TestAnnotation(id=3,msg=“hello annotation”)
public class Test {

}
注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

int id() default -1;

String msg() default “hello”;

}

注解数据获取

参考:https://blog.csdn.net/u014207606/article/details/52293939
A、对于运行时注解,@Retention(RetentionPolicy.RUNTIME) 获取如下:

类的注解获取:
1.先判断是否用了某个注解?
通过 Class 对象的 isAnnotationPresent() 方法判断。
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
}
2、然后通过 getAnnotation() 方法来获取 Annotation 对象,得到获取到类的注解。

@TestAnnotation()
public class Test {
 
    public static void main(String[] args) {
 
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
 
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
 
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
 
    }
 
}

方法或者成员注解获取:
通过反射获取到成员或者方法,在获取到注解,得到注解数据。

@TestAnnotation(msg="hello")
public class Test {
 
    @Check(value="hi")
    int a;
 
 
    @Perform
    public void testMethod(){}
 
 
    @SuppressWarnings("deprecation")
    public void test1(){
        Hero hero = new Hero();
        hero.say();
        hero.speak();
    }
 
 
    public static void main(String[] args) {
 
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
 
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            //获取类的注解
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
 
 
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //获取一个成员变量上的注解
            Check check = a.getAnnotation(Check.class);
 
            if ( check != null ) {
                System.out.println("check value:"+check.value());
            }
 
            Method testMethod = Test.class.getDeclaredMethod("testMethod");
 
            if ( testMethod != null ) {
                // 获取方法中的注解
                Annotation[] ans = testMethod.getAnnotations();
                for( int i = 0;i < ans.length;i++) {
                    System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                }
            }
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        }   
 
 
    }
 
}

B、编译时注解@Retention(RetentionPolicy.SOURCE),需要通过注解解释器获取

注解解释器后续再介绍。先可以参考https://segmentfault.com/a/1190000009756015

总结

注解的基本语法,创建如同接口,但是多了个 @ 符号。
注解的元注解5个:@Retention、@Documented、@Target、@Inherited、@Repeatable
注解的属性:即接口的成员。一般是基本数据类型
运行注解的提取需要借助于 Java 的反射技术,反射比较慢,所以注解使用时也需要谨慎计较时间成本。(定义注解时使用了@Retention(RetentionPolicy.RUNTIME)修饰,JVM才会在装载class文件时提取保存在class文件中的注解,该注解才会在运行时可见,这样我们才能够解析。)
JAVA默认的注解@Deprecated、@Override、@SuppressWarnings、@FunctionalInterface等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值