转载自 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原理和用法相关推荐
- Java基础 --- 注解 Annotation
Java基础 --- 注解 Annotation Java注解 Java自带的标准注解 自定义注解 Java注解 Java注解它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadat ...
- 夯实 Java 基础 - 注解
夯实 Java 基础 - 注解 不知道大家有没有一种感觉,当你想要了解某个知识点的时候,就会发现好多技术类 APP 或者公众号在推一些关于这个知识点的文章.也许这就是大数据的作用,这也说明总有人比你抢 ...
- Java基础-注解和反射
Java基础-注解和反射 前言 对于注解,我主要还是在自定义APT还有运行时反射获取类来让自己能够构建出复用性更高的代码逻辑. 知识点1-注解: 注解的应用场景由元注解@Retention来进行指定, ...
- 【Java基础】HashMap原理详解
[Java基础]HashMap原理详解 HashMap的实现 1. 数组 2.线性链表 3.红黑树 3.1概述 3.2性质 4.HashMap扩容死锁 5. BATJ一线大厂技术栈 HashMap的实 ...
- java原理教程,java基础之运行原理(一),java基础运行原理
java基础之运行原理(一),java基础运行原理 java的核心配置:JDK JDK主要包括三个部分 1.Jre:java的运行环境 2.Java的工具:java的编译器(java.c.exe). ...
- Java自定义注解Annotation的实现原理
文章目录 1.什么是注解? 2.注解的用处: 3.注解的原理: 4.元注解: 5.常见标准的Annotation: 6.自定义注解: 7.自定义注解实例: 1.什么是注解? 对于很多初次接触的开发 ...
- Java基础笔记 – Annotation注解的介绍和使用 自定义注解
1.Annotation的工作原理: JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型.该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的c ...
- java基础- 注解和反射
1. 注解(Annotation) 1. 什么是注解 Annotation是从JDK5.0开始引入的新技术. Annotation的作用 : 不是程序本身,可以对程序作出解释.(这一点和注释(comm ...
- Java基础——注解的初步认识
目录 注解(Annotation)的理解 Annotation的使用示例 自定义注解 JDK中四个基本元注解 利用反射获取注解信息 可重复注解 注解(Annotation)的理解 Annotation ...
最新文章
- Linux高性能网络:协程系列09-协程性能测试
- 事物处理@Transactional
- python中的进程
- html登录界面_使用数据库制作一套注册登录系统
- 微软 MVP 福利大赏
- Java请求参数检查,Java如何检查servlet请求中是否存在参数?
- 怎么理解Condition
- 吃完饭打嗝原因及治疗方法(分享)
- No module named 'tensorflow.contrib'
- 借用implicit创建我们自己的布尔数据类型-create MyBool data type by implicit
- Jmeter测试——java测试脚本编写
- 人工神经网络图像识别,人脸识别神经网络模型
- python jsonrpc_python-jsonrpc框架实现JsonRPC协议的web服务
- STM8L101+si4463低功耗和自动唤醒配置
- CGAL学习之路(三):CGAL读写点云
- 关于 Axure 动态面板
- 佛珠的颗数有什么讲究
- 《目标检测蓝皮书》第4篇 经典热门网络结构
- Echarts Y轴遮挡解决方案
- MT25QU128 (flash) 简介
热门文章
- windbg 符号表
- deque与vector的主要区别
- 从send函数和sendto函数参数的不同看TCP和UDP的差别
- Android 图形架构
- BBR如何让Spotify流媒体更流畅?
- 腾讯技术直播间 | 当感性遇上理性,当魔术遇上数学
- Facebook开源计算机视觉目标检测平台Detectron
- Python pip使用国内镜像
- Git的基础知识和常用命令
- TensorFlow 1.0正式发布