Java注解(Annotation)详解

转:

Java注解(Annotation)详解

幻海流心

2018.05.23 15:20 字数 1775 阅读 380评论 0喜欢 1

Java注解(Annotation)详解

1.Annotation的概念

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

  • 注解是一种可以添加到Java源代码的元数据.
  • 类,方法,变量,参数,包都可以被注解.
  • 注解对注解的代码并没有直接的影响.
  • 注解仅仅是个标记.注解之所以起作用是对其解析后做了相应的处理

2.Annotation分类

  • 标准Annotation

    • 标准Annotation是指Java内置的三个Annnotaion:
    • @Override:用于修饰此方法覆盖了父类的方法.
    • @Deprecated:用于修饰已经过时的方法.
    • @SuppressWarnnings:用于通知java编译器禁止特定的编译警告.
  • 元Annotation(注解的注解)
    • 元Annotation是用来定义Annotation的Annotation
    • 元Annotation可以定义Annotation的作用范围,使用在什么元素上等
    • 元注解共有四种@Retention, @Target, @Inherited, @Documented
  • 自定义Annotation

3.元Annotation

  • @Retention:注在其他的注解A上,用来说明A的保留范围,可选值 SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为 CLASS

    • SOURCE:A只保留在源码中,A会被编译期忽略.(源码可用)
    • CLASS:A会通过编译保存在CLASS文件中,但会被JVM在运行时忽略,运行时不可见.(源码+CLASS可用)
    • RUNTIME:A会被JVM获取,并在运行时通过反射获取.(源码+CLASS+运行时均可用)
  • @Target:注在其他的注解A上,用来限制A可用修饰那些程序元素.未标注Target表示无限制,可修饰所有元素.
    • ANNOTATION_TYPE: A可以应用到其他注解上
    • CONSTRUCTOR: A可以使用到构造器上
    • FIELD: A可以使用到域或属性上
    • LOCAL_VARIABLE: A可以使用到局部变量上。
    • METHOD: A可以使用到方法上。
    • PACKAGE: A可以使用到包声明上。
    • PARAMETER: A可以使用到方法的参数上
    • TYPE: A可以使用到类,接口(包括注解),或枚举的声明上
  • @Inherited:默认情况下,父类的注解不会被子类继承.
    • Inherited注在其他的注解A上.
    • 只有当A是注解在类Class上面,Inherited才会起作用,其他任何情况下无效果.
    • 当A注解在类C上面,则C的所有子孙类,都会继承应用A注解;
  • @Documented:注在其他的注解A上,A将会作为Javadoc产生的文档中的内容。注解都默认不会成为成为文档中的内容。

4.自定义Annotation

  1. 创建自定义Annotation流程

    • public @interface 自定义注解名称

      public @interface CustomAnnotation{***}
      
      
    • 设置自定义Annotation的保留范围和目标,Retention和Target是最重要的两个元Anitation.
      @Retention( RetentionPolicy.RUNTIME )
      @Target( ElementType.TYPE )
      public @interface CustomAnnotation{***}
      
    • 设置自定义Annotation的注解参数(注解成员)
      • 注解参数支持的数据类型

        • 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
        • String类型
        • Class类型
        • enum类型
        • Annotation类型
        • 以上所有类型的一维数组
      • 注解参数声明方式
        @Retention( RetentionPolicy.RUNTIME )
        @Target( ElementType.TYPE )
        public @interface CustomAnnotation{
            //注解参数类型可以是1-6中任一种,包括枚举
            public enum Skill{JAVA,ANDROID,IOS}
            Skill mySkill() default Skill.ANDROID;
            String attr1();
            //可以使用default设置默认值
            int attr2() default 100;
            //修饰符只能用public
            public boolean attr3() default false;
        }
        @Retention( RetentionPolicy.RUNTIME )
        @Target( ElementType.TYPE )
        public @interface CustomAnnotation{
            //只有一个注解参数,使用value()
            String value();
        }
        
        • 自定义Annotation的参数类型必须满足上一条1到6中的范围.
        • 自定义Annotation的参数访问方法只能是public,或不写.
        • 自定义Annotation的参数可以加 default 设置默认值.
        • 自定义Annotation若只有1个参数,使用value().
  2. 自定义Annotation的注解参数的默认值

    注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

    示例:
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AnotherAnnotation{
        String author() default "";
        int age() default -1;
    }
    
  3. 使用刚刚创建的自定义注解
    @CustomAnnotation(attr1 = "属性1", attr2 = 90, attr3 = true)
    public class AnnotationTestClass{
        ***
    }
    

5.Annotation解析

  • 运行时 Annotation 解析

    运行时 Annotation 指 @Retention 为 RUNTIME 的 Annotation
    - Class,Method,Field中都有以下3个方法可以调用
    - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) 按照传入的参数获取指定类型的注解。返回null说明当前元素不带有此注解。
    - public final boolean isAnnotationPresent(Class<? extends Annotation> annotationType) 检查传入的注解是否存在于当前元素。
    - public Annotation[] getAnnotations() 返回该元素的所有注解,包括没有显式定义该元素上的注解。
    - 运行时 Annotation 解析示例
    public void testCustomAnnotation() { try { Class cls = Class.forName("com.jet.annotation.AnnotationTestClass"); CustomAnnotation customAnnotation = (CustomAnnotation)cls.getAnnotation(CustomAnnotation.class); System.out.println("customAnnotation mySkill:" + cus.mySkill()); System.out.println("customAnnotation attr1:" + cus.attr1()); System.out.println("customAnnotation attr2:" + cus.attr2()); } catch (ClassNotFoundException e) { e.printStackTrace(); } }

  • 编译时 Annotation 解析

    编译时 Annotation 指 @Retention 为 CLASS 的 Annotation,甴编译器自动解析


6.编译时Annotation解析

编译时Annotation解析 相对复杂,下面单独进行分析

首先申明:下面内容仅仅讨论 编译时Annotation的解析

  1. 编译时Annotation的解析,是由Annotation Processor完成
  2. Annotation Processor(注解处理器)
    • 注解处理器是一个在javac中的,用来在编译时扫描和处理注解的工具
    • 我们可以为特定的注解,注册自定义的注解处理器
    • 在编译期间,JVM会自动运行注册过的注解处理器
    • 一个注解的Annotation Processor,以Java代码(或者编译过的class)为输入,生成.java文件作为输出.这意味着我们可以生成新的Java代码!这些生成的Java代码是在生成的.java文件中,新生成的.java文件会和普通的手动编写的Java源代码一样被javac编译
  3. 每一个注解处理器都是继承于AbstractProcessor,需要关注的有以下4个方法
public abstract class AbstractProcessor implements Processor {

    //对一些工具进行初始化
    public synchronized void init(ProcessingEnvironment processingEnv)

    //你在这里定义你的注解处理器注册到哪些注解上,必须指定;
    //它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
    public Set<String> getSupportedAnnotationTypes()

    //指定该注解处理器使用的JAVA版本,通常返回SourceVersion.latestSupported()
    public SourceVersion getSupportedSourceVersion()

    //真正生成java代码的地方
    //annotations:请求处理的注解类型集合
    //roundEnv:可以让你查询出包含特定注解的被注解元素,相当于“有关全局源码的上下文环境”
    //如果返回 true,则这些注解已声明并且不要求后续 Processor 处理它们;
    //如果返回 false,则这些注解未声明并且可能要求后续 Processor 处理它们
    public abstract boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv)

}
  1. 自定义注解处理器,就是继承AbstractProcessor并重写上述4个方法

关于编译时Annotation解析,这里推荐一篇文章【Android】注解框架(三)-- 编译时注解,手写ButterKnife,按照文章上面流程敲一遍代码,相信可以对自定义注解的创建及解析有一个深入的了解!

原文地址:https://www.cnblogs.com/libin6505/p/11227101.html

时间: 2024-08-03 04:24:23

Java注解(Annotation)详解的相关文章

Java注解Annotation详解

注解是一种标记,在程序中加上某种注解就等于为程序打上了某种标记,在javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上是否存在标记,存在什么标记,就去干相应的事.标记可以加在包,类,字段,方法,方法的参数以及局部变量上. 自定义注解及其应用 1).定义一个最简单的注解 public @interface MyAnnotation {     //...... } 2).把注解加在某个类上: @MyAnnotation public class AnnotationTest{  

Java自定义注解Annotation详解

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事.标记可以加在包,类,字段,方法,方法的参数以及局部变量上. 自定义注解及其应用 1).定义一个最简单的注解 public @interface MyAnnotation { //...... } 2).把注解加在某个类上: @MyAnnotation public class Annot

java 注解——使用详解

在一些强大的第三方框架中我们常常可以见到注解的身影.xUtils.Retrofit等. 那么注解到底有什么魅力和好处让我们在设计种种框架的时候用到它呢? 对于注解的理解: (仅仅为个人理解) 1,我们通过注解给某个常量.方法或者类一个标记.那么这些常量就有了某种特征或者某种标记. 2,这些标记不参与我们的逻辑处理.这也是为什么它会写在方法或者类的外面的原因. 3,但是我们可以通过获取方法上的标记即注解来间接的影响程序的逻辑. 4,注解是被动的,它影响程序取决于程序员是否去使用它. 由此看来,注解

Java 基础之--注解Annotation详解

自定义注解入门: public @interface Annotation01 { //set default value ""; String value() default ""; } 1.保持策略@Retention annotation: 告知编译器如何去运行,default is RetentionPolicy.CLASS (1).RetentionPolicy.CLASS : -->会将注解保存在class 文件中,但运行时候不会被virtual

Java反射机制详解

Java反射机制详解 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制. 1.关于Class 1.Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性    2.对象照镜子后(反射)可以得到的信息:某个类的数据成员名.方法和构造器.某个类到底实现

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(一)

Spring更新到3.0之后,其MVC框架加入了一个非常不错的东西——那就是REST.它的开放式特性,与Spring的无缝集成,以及Spring框架的优秀表现,使得现在很多公司将其作为新的系统开发框架.大象根据实际的项目经验,以之前SSH2例子为基础,对其进行一次大改造,详细的为大家讲解如何实现SSM3全注解式的开发. 这次大象将采取两种构建方式,一是很多人喜欢用的MyEclipse,另一个,则是用Eclipse+Maven.这一篇,将主要讲解开发环境设置与Maven构建方式. 1. 开发环境

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(五)

这是本系列的最后一篇,主要讲一下FreeMarker模板引擎的基本概念与常用指令的使用方式.     一.FreemMarker基本概念     FreemMarker是一个用Java语言编写的模板引擎,它是一个基于模板来生成文本输出的一个工具.是除了JSP之外被使用得最多的页面模板技术之一,另一个比较有名的模板则是Velocity.     用户可以使用FreeMarker来生成所需要的内容,通常由Java提供数据模型,FreeMarker通过模板引擎渲染数据模型,这样最终得到我们想要的内容.

java移位运算符详解[转]

java移位运算符不外乎就这三种:<<(左移).>>(带符号右移)和>>>(无符号右移). 1. 左移运算符 左移运算符<<使指定值的所有位都左移规定的次数. 1)它的通用格式如下所示: value << num num 指定要移位值value 移动的位数. 左移的规则只记住一点:丢弃最高位,0补最低位 如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.如对int型移动33位,实际上只移动了332=1位. 2)运算规则 按

java 代理模式详解

java 动态代理(JDK和cglib) 设计模式这东东每次看到就明白可过段时间又不能很流利的说出来,今天就用详细的比喻和实例来加深自己的理解(小弟水平不高有不对的地方希望大家能指出来). (1)代理这个词生活中有很多比如在街边卖手机卡.充公交地铁卡的小商店他们都起了代理的作用,java中的代理跟这些小店商的作用是一样的.再比如我想在淘宝上开个服装店但又没有货源怎么办,这时候我就要跟淘宝上某一卖家联系做他的代理.我跟我的商家都要卖衣服(就好比我们都继承了卖衣服的接口sellClothesInte