转载自 http://www.wolfbe.com/detail/201608/265.html

在很多java代码中都可以看到诸如@Override、@Deprecated、@SuppressWarnings这样的字符,这些就是注解Annotation。注解最早在jdk5中被引入,现在已经成为java平台很重要的一部分了,很多的框架程序中也喜欢使用注解,如Spring、Mybatis等。

那么,什么是注解呢?注解就是元数据,一种描述数据的数据,通俗一点就是为程序的元素(类、方法、成员变量)加上更直观的说明,这些说明信息是与程序的业务逻辑无关的。但是,我们可以通过java的反射机制来获取Annotation的信息,并根据这些信息来对程序进行赋值、分发等操作。
java5.0定义了4个标准的meta-annotation元注解,它们被用来提供对其它annotation类型作说明,四种元注解如下:
  • @Target;
  • @Retention;
  • @Inherited;
  • @Documented;
下面详细说明这四种元注解的作用:
@Target
     被用于描述注解的使用范围,即注解可以用在所修饰对象的什么地方,取值可以是ElementType中的一种:
  • CONSTRUCTOR:用于描述构造器;
  • FIELD:用于描述域;
  • LOCAL_VARIABLE:用于描述局部变量;
  • METHOD:用于描述方法;
  • PACKAGE:用于描述包;
  • PARAMETER:用于描述参数;
  • TYPE:用于描述类、接口、注解类型或枚举;
@Target(ElementType.TYPE)
public @interface Exculde{
/**
* 名称,默认值为""
* @return
*/
public String name() default "";
}
@Target(ElementType.FIELD)
public @interface Inject{
/**
* id,默认值为""
* @return
*/
public String id() default "";
/**
* 类,默认值为""
* @return
*/
public Class clazz() default Object.class;
}
上面定义了两个注解,注解@Exculde只能用于修饰类、接口、注解、枚举,注解@Inject只能修饰类型的域,如:
@Exculde(name="admin")
public class User{
@Inject(id="username",clazz=String.class)
private String username;
}
@Retention
     用于描述注解的生命周期,即注解能在源码到JVM装载过程中的哪一个级别上有效。有些annotation仅出现在源码中,被编译器丢弃;有些annotation能被编译进class文件中,可能被JVM忽略;有些annotation不但能够被编译进class文件,而且能够在class文件被装载时被读取。这三种情况对应RetentionPoicy的三种取值:
  • SOURCE:源码文件中保留;
  • CLASS:class文件中保留;
  • RUNTIME:运行时保留;
@Inherited
     用于描述注解是可以被继承的,如果一个使用了@Inherited修饰的annotation被用于一个class,那么这个annotation也将被用于这个class的子类。@Inherited是一个标记注解,没有参数选项,它修饰的annotation是被标记的class的子类所继承,类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当使用java的反射去获取一个@Inherited修饰的annotation时,反射检查将递归检查,检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
@Documented
用于描述注解信息应该被作为被标注的程序的公共API,即应该把注解信息保留文档中。@Documented也是一个标记注解,没有参数选项。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Exculde{
/**
* 名称注解,默认值为""
* @return
    */
public String name() default "";
}
如果你看过了上面的元注解,如果还不能理解也没关系,下面我们通过自定义注解来进一步理解元注解。
自定义注解需要使用@interface,类似于定义一个类使用class,但定义注解时不能再继承其它的类或者接口,它已经自动继承了java.lang.annotation.Annotation接口。@interface用来声明一个注解,其中的每一个方法实际上声明了一个配置参数,方法的名称就是参数的名称,方法的返回值类型就是参数的类型,也可以使用default来声明参数的默认值。
定义注解的格式如下:
public @interface 注解名{ 定义体 }
注解参数可支持的数据类型如下:
  • 基本类型;
  • Class;
  • String;
  • Enum;
  • Annotation;
  • 以上所有类型的数组形式;
下面定义一个类似于Spring的注解,用于向实例对象注入属性的值:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject{
/**
* ID,默认值为""
* @return
*/
public String id() default "";
/**
* 类,默认值为""
* @return
*/
public Class clazz() default Object.class;
}
把@Inject标注在类UserAction的属性上:
public class UserAction {
@Inject(id="userService",clazz=UserService.class)
private UserService userService;
}
在IOC容器框架中,对象都会被自动初始化,如果我们要实现IOC的这种功能,我们应该为加上@Inject注解的属性userService注入它的值。首先我们应该通过反射获取userService的域对象field,通过field获取@Inject注解的信息,然后根据注解的id和clazz得到它依赖的值:
Inject inject = field.getAnnotation(Inject.class);
String id = inject.id();
Class clazz = inject.clazz();
Object userService = Class.forName(clazz.getName).newInstance();
field.setAccessible(true);
field.set(object,userService);
上面代码中,调用field.getAnnotation(Inject.class)获取到@Inject的对象,然后获取@Inject的id和clazz值,通过反射实例化clazz的对象,再反射赋值给field。这就是Spring那些框架的依赖注入的实现原理,有兴趣的可以自己再优化一下。
读取类的注解信息还有其它的几个方法,在此不再一一说明,可以自行研究java.lang.reflect包。经过上面的说明,由此我们也可以知道注解仅仅是一种元数据,增强类、属性、参数的描述,使用注解的关键在于获取注解的信息,再通过反射的手段来实现注解想达成的功能。

java基础-注解Annotation原理和用法相关推荐

  1. Java基础 --- 注解 Annotation

    Java基础 --- 注解 Annotation Java注解 Java自带的标准注解 自定义注解 Java注解 Java注解它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadat ...

  2. 夯实 Java 基础 - 注解

    夯实 Java 基础 - 注解 不知道大家有没有一种感觉,当你想要了解某个知识点的时候,就会发现好多技术类 APP 或者公众号在推一些关于这个知识点的文章.也许这就是大数据的作用,这也说明总有人比你抢 ...

  3. Java基础-注解和反射

    Java基础-注解和反射 前言 对于注解,我主要还是在自定义APT还有运行时反射获取类来让自己能够构建出复用性更高的代码逻辑. 知识点1-注解: 注解的应用场景由元注解@Retention来进行指定, ...

  4. 【Java基础】HashMap原理详解

    [Java基础]HashMap原理详解 HashMap的实现 1. 数组 2.线性链表 3.红黑树 3.1概述 3.2性质 4.HashMap扩容死锁 5. BATJ一线大厂技术栈 HashMap的实 ...

  5. java原理教程,java基础之运行原理(一),java基础运行原理

    java基础之运行原理(一),java基础运行原理 java的核心配置:JDK JDK主要包括三个部分 1.Jre:java的运行环境 2.Java的工具:java的编译器(java.c.exe). ...

  6. Java自定义注解Annotation的实现原理

    文章目录 1.什么是注解? 2.注解的用处: 3.注解的原理: 4.元注解: 5.常见标准的Annotation: 6.自定义注解: 7.自定义注解实例: 1.什么是注解?   对于很多初次接触的开发 ...

  7. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    1.Annotation的工作原理: JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型.该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的c ...

  8. java基础- 注解和反射

    1. 注解(Annotation) 1. 什么是注解 Annotation是从JDK5.0开始引入的新技术. Annotation的作用 : 不是程序本身,可以对程序作出解释.(这一点和注释(comm ...

  9. Java基础——注解的初步认识

    目录 注解(Annotation)的理解 Annotation的使用示例 自定义注解 JDK中四个基本元注解 利用反射获取注解信息 可重复注解 注解(Annotation)的理解 Annotation ...

最新文章

  1. Linux高性能网络:协程系列09-协程性能测试
  2. 事物处理@Transactional
  3. python中的进程
  4. html登录界面_使用数据库制作一套注册登录系统
  5. 微软 MVP 福利大赏
  6. Java请求参数检查,Java如何检查servlet请求中是否存在参数?
  7. 怎么理解Condition
  8. 吃完饭打嗝原因及治疗方法(分享)
  9. No module named 'tensorflow.contrib'
  10. 借用implicit创建我们自己的布尔数据类型-create MyBool data type by implicit
  11. Jmeter测试——java测试脚本编写
  12. 人工神经网络图像识别,人脸识别神经网络模型
  13. python jsonrpc_python-jsonrpc框架实现JsonRPC协议的web服务
  14. STM8L101+si4463低功耗和自动唤醒配置
  15. CGAL学习之路(三):CGAL读写点云
  16. 关于 Axure 动态面板
  17. 佛珠的颗数有什么讲究
  18. 《目标检测蓝皮书》第4篇 经典热门网络结构
  19. Echarts Y轴遮挡解决方案
  20. MT25QU128 (flash) 简介

热门文章

  1. windbg 符号表
  2. deque与vector的主要区别
  3. 从send函数和sendto函数参数的不同看TCP和UDP的差别
  4. Android 图形架构
  5. BBR如何让Spotify流媒体更流畅?
  6. 腾讯技术直播间 | 当感性遇上理性,当魔术遇上数学
  7. Facebook开源计算机视觉目标检测平台Detectron
  8. Python pip使用国内镜像
  9. Git的基础知识和常用命令
  10. TensorFlow 1.0正式发布