本篇文章将从元注解、自定义注解的格式、自定义注解与反射结合的简单范例、以及自定义注解的应用来说一说java中的自定义注解。

一、元注解

元注解也就是注解其他注解(自定义注解)的java原生的注解,Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited                                                                                                                                                                                   前两个比较常用,后两个基本很少用到。

 @Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  取值(ElementType)有以下7个枚举类型:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

  使用实例:  

@Target(ElementType.METHOD)
public @interface MyTarget
{
String value();
}

  @Retention:

  @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  取值(RetentionPoicy)有以下3个枚举类型:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

  Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}

  @Documented:

  @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

  @Inherited:

  @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

二、自定义注解的格式

  public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

    1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
    2.String类型
    3.Class类型
    4.enum类型
    5.Annotation类型
    6.以上所有类型的数组

  当注解中属性名为value是,在对其赋值时可以不指定属性的名称而直接写上属性值即可,除了value以外的其他值都要使用name = value这种赋值方式,明确指定到底给谁赋值。

  一个方法可以由多个注解修饰

  当我们使用@interface自行定义Annotation时,实际上是自动继承了java.lang.annotation.Annotation接口,由编译程序自动为您完后其他产生的细节。在定义Annotation类的时候不能继承其他Annotation类型的接口。

三、自定义注解与反射结合使用的简单例子

 自定义注解类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name();
String pass();
}

  用@Target(ElementType.METHOD)定义MyAnnotation注解的使用时机是方法。

  用@Retention(RetentionPolicy.RUNTIME)定义MyAnnotation注解会被虚拟机读取。

 使用注解的类和方法:

public class MyTest {
@Deprecated
@MyAnnotation(name = "admin", pass = "*****")
public void output(){
System.out.println("output something!");
}
}

  用@Deprecated定义output方法是不建议被使用的方法。

  用@MyAnnotation(name = "admin", pass = "*****")注释output方法,并为属性赋值

 利用反射实现功能的类:

public class MyReflection {
public static void main(String[] args) throws Exception {
MyTest myTest = new MyTest();
Class<MyTest> c = MyTest.class;
Method method = c.getMethod("output", new Class[]{}); //判断该方法是否有MyAnnotation注解
if(method.isAnnotationPresent(MyAnnotation.class)) {
method.invoke(myTest, new Class[]{}); //通过反射获取myAnnotation对象
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String name = myAnnotation.name();
String pass = myAnnotation.pass(); System.out.println(name + ", " + pass);
} //获取当前方法的所有注解的对象,注意必须是运行时注解这里才能获取。
//因为是通过反射获取的所以显然应该是运行时的注解才会获取。
Annotation[] annotations = method.getAnnotations(); //遍历输出注解的名字
for(Annotation annotation : annotations)
{
System.out.println(annotation.annotationType().getName());
}
}
}

 运行结果:

  output something!

  admin, *****

  java.lang.Deprecated

  wenge.annotation.MyAnnotation

这段程序的作用是用反射运行由自定义注解注释的方法,获取自定义注解的对象并进行操作(输出了属性),得到output方法的所有注解的对象。这里需要说明的一点是反射只能对运行时注解(也就是用@Retention(RetentionPolicy.RUNTIME)注释的注解)进行操作。

 这里就是用一个简单的例子说明一下自定义注解与反射的使用。

四、自定义注解与反射结合的应用场景

 我觉得自定义注解与反射最好的应用场景就是junit。在junit4以前是用方法名以test打头实现的,而在junit4以后就是应用自定义注解实现识别测试方法。但是不管怎么用说白了还是反射,只是用了一种比较好的实现方式而已。而且这种方式的确很优雅。

 junit执行的一般流程是:

  1、首先获得待测试类所对应的Class对象。

  2、然后通过改class对象获得当前类中所有public方法所对应的Method数组。

  3、遍历该method数组,取得每一个Method对象。

  4、调用每个Method对象的isAnnotationPresent(Test.class)方法,判断该方法是否被@test注释。

  5、如果isAnnotationPresent返回true,调用method.invoke()方法执行该方法,否则不执行。

 准备下次写一篇关于junit源码的文章,在这里就不细说了。

javase基础回顾(四) 自定义注解与反射的更多相关文章

  1. Java利用自定义注解、反射实现简单BaseDao

    在常见的ORM框架中,大都提供了使用注解方式来实现entity与数据库的映射,这里简单地使用自定义注解与反射来生成可执行的sql语句. 这是整体的目录结构,本来是为复习注解建立的项目^.^ 好的,首先 ...

  2. java自定义注解与反射

    java注解与反射一.Java中提供了四种元注解,专门负责注解其他的注解,分别如下 1.@Retention元注解,表示需要在什么级别保存该注释信息(生命周期).可选的RetentionPoicy参数 ...

  3. java基础知识:自定义注解

    转自 深入了解注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解的作用就是负责注解其他注解.J ...

  4. JAVA-注解(2)-自定义注解及反射注解

    自定义注解开发 1.开发一个注解类 开发一个注解类的过程,非常类似于开发一个接口,只不过需要通过@interface关键字来声明 2.使用元注解修饰注解的声明 所谓的原注解是用来修饰注解声明的注释,可 ...

  5. springboot使用自定义注解和反射实现一个简单的支付

    优点: 未使用if else,就算以后增加支付类型,也不用改动之前代码 只需要新写一个支付类,给添加自定义注解@Pay 首先: 定义自定义注解 Pay 定义 CMBPay ICBCPay 两种支付 根 ...

  6. Spring AOP基础概念及自定义注解式AOP初体验

    对AOP的理解开始是抽象的,看到切点的匹配方式其实与正则表达式性质大致一样就基本了解AOP是基本是个什么作用了.只是整个概念更抽象,需要具化理解.下图列表是AOP相关概念解释,可能也比较抽象^_^ 比 ...

  7. Android中的自定义注解(反射实现-运行时注解)

    预备知识: Java注解基础 Java反射原理 Java动态代理 一.布局文件的注解 我们在Android开发的时候,总是会写到setContentView方法,为了避免每次都写重复的代码,我们需要使 ...

  8. JavaSE基础第四篇

    1.参数传递   2,方法的重载 方法的参数的个数.类型.顺序 跟修饰符.返回值无关   3.构造方法: return 表示当前方法执行结束,后面不能写任何语句   4工程导入 单个.java文件粘贴 ...

  9. javase基础回顾(一)ArrayList深入解析 解读ArrayList源代码(JDK1.8.0_92)

    我们在学习这一块内容时需要注意的一个问题是 集合中存放的依然是对象的引用而不是对象本身. List接口扩展了Collection并声明存储一系列元素的类集的特性.使用一个基于零的下标,元素可以通过它们 ...

随机推荐

  1. SqlParameter参数类型为int32时候的传值陷阱

    前2天在使用SqlParameter传递参数的时候遇到一个小坑,这里分享一下. SqlParameter para=new SqlParameter("@IsDeleted",0) ...

  2. RSA加密算法 C++实现

    上信息安全课,老师布置了几个大作业,其中一个为RSA加密算法的实现,不能用Java写.出于兴趣,决定尝试.完成之后,为了便于查找,于是写下这篇文章,以备后续查看.也供大家一起学习,一起进步. 1.预备 ...

  3. CSS样式表初学,比C#和JS简单

    今天咱们一起来看下CSS样式表的基本基础 经常看博客或者喜欢钻研代码这一类的人对CSS可能有所耳闻,但具体的可能不是很清楚 那什么是CSS呢?与HTML又有什么区别呢?今天咱们就来说道下这个CSS C ...

  4. vue实现全选效果

    vue实现全选效果 接触vue快半年了,记得刚用vue做项目的时候遇到一个全选功能,当时到处百度也没有找到怎么实现,最后还是用了jquery进行dom操作实现的. 今天没事就顺手写了一个,感觉很简单, ...

  5. C语言学习第二章

    今天开始学习常量,变量,基本数据类型,printf()函数和scanf()函数,算术运算符. 首先常量:是在程序中保持不变的量 变量:编写程序时,常常需要将数据存储在内存中,方便后面使用这个数据或者修 ...

  6. 探讨数据进行AES加密和解密以及.NET Core对加密和解密为我们提供了什么?

    前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...

  7. Dora.Interception: 一个为.NET Core度身定制的AOP框架

    多年从事框架设计开发使我有了一种强迫症,那就是见不得一个应用里频繁地出现重复的代码.之前经常Review别人的代码,一看到这样的程序,我就会想如何将这些重复的代码写在一个地方,然后采用“注入”的方式将 ...

  8. 在Angular项目下使用Umeditor

    Umeditor是百度旗下的开源富文本编辑器项目,目前用于百度贴吧,是ueditor的迷你版本. 公司的Angular后台管理项目需要上传一些新闻,用Umeditor十分适合.但是目前官方只提供Jsp ...

  9. ms_celeb_1m数据提取(MsCelebV1-Faces-Aligned.tsv)python脚本

    本文主要介绍了如何对MsCelebV1-Faces-Aligned.tsv文件进行提取 原创by南山南北秋悲 欢迎引用!请注明原地址 http://www.cnblogs.com/hwd9654/p/ ...

  10. hdu4027线段树

    https://vjudge.net/contest/66989#problem/H 此题真是坑到爆!!说好的四舍五入害我改了一个多小时,不用四舍五入!!有好几个坑点,注意要交换l,r的位置,还有输出 ...