本篇文章参考的相关资料连接:php
- 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3
- 注解基础与高级应用:http://linbinghe.com/2017/ac8515d0.html
- 秒懂注解:https://blog.csdn.net/briblue/article/details/73824058
这篇文章参考了不少其余文章的写做思路和篇章内容,主要用来帮助咱们更好的理解Java中注解的使用,解开注解的神秘面纱。html
维基百科上对注解的解释是这样的:java
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据[1]。Java语言中的类、方法、变量、参数和包等均可以被标注。和Javadoc不一样,Java标注能够经过反射获取标注内容。在编译器生成类文件时,标注能够被嵌入到字节码中。Java虚拟机能够保留标注内容,在运行时能够获取到标注内容[2]。 固然它也支持自定义Java标注[3]。app
咱们能够这样理解,就是咱们在类、方法、变量、参数等元素上面贴一个标签,而且咱们可以在运行时动态的获取到这些标签。框架
咱们在方法上贴了一个名为RoleCheck的标签,它里面有一个标签的描述信息为level。在运行该方法时,咱们同时能够获取到这个标签及里面的描述信息。具体的语法和更多的内容咱们将会在下面的文章中分享到。ide
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中
函数
做用在代码的注解是工具
做用在其余注解的注解(或者说 元注解)是:测试
关于Target:spa
你能够这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
类比到标签,本来标签是你想张贴到哪一个地方就到哪一个地方,可是由于 @Target 的存在,它张贴的地方就很是具体了,好比只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值
- ElementType.ANNOTATION_TYPE 能够给一个注解进行注解
- ElementType.CONSTRUCTOR 能够给构造方法进行注解
- ElementType.FIELD 能够给属性进行注解
- ElementType.LOCAL_VARIABLE 能够给局部变量进行注解
- ElementType.METHOD 能够给方法进行注解
- ElementType.PACKAGE 能够给一个包进行注解
- ElementType.PARAMETER 能够给一个方法内的参数进行注解
- ElementType.TYPE 能够给一个类型进行注解,好比类、接口、枚举
从 Java 7 开始,额外添加了 3 个注解:
内置注解咱们能够直接用到就只有lang中的几个,annotation中几个注解的都是做用在其余注解上的,咱们称之为元注解。其余注解就是咱们的自定义注解!
使用@interface自定义注解,会自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其余细节。
在定义注解时,不能继承其余的注解或接口。
@interface用来声明一个注解,其中的每个方法其实是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。能够经过default来声明参数的默认值。
public @interface RoleCheck {
int[] level() default 0;
}
好比上面这个代码中,咱们定义一个名叫RoleCheck的注解(标签),和一个名为level配置参数(一个标签描述信息,是数值型的),而且默认值为0。
可是如今这个注解并不能直接使用,由于咱们尚未用元注解去描述这个注解。
1.这个注解在哪里保存呢?
@Retention,固然是RUNTIME:JVM将在运行期间保留注解,所以能够经过反射机制读取注解的信息。
2.这个注解的运用场景是哪里?也就是说它被写在哪里?
@Target,咱们选择 ElementType.METHOD ,它能够给方法进行注解。
3.用不用@Document?
@Documented 表示含有该注解类型的元素(带有注释的)会经过javadoc或相似工具进行文档化,Documented是一个标记注解(相似@Override 这种只须要一个简单的声明便可的注解即为标记注解),没有成员。咱们这里用或不用均可以,由于咱们不涉及文档化处理,可是仍是写上了。
最终注解将变成以下的样子:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RoleCheck {
int[] level() default 0;
}
说明:
若是只有一个参数成员,最好把参数名称设为”value”,后加小括号。注解在只有一个元素且该元素的名称是value的状况下,在使用注解的时候能够省略“value=”,直接写须要的值便可。也就是下面这样。
public @interface RoleCheck { int value() default 0; } //用的时候,不用写参数名称了,直接写值 @RoleCheck(1) public void doSomeThing() { ..... }
//注解没有属性
@RoleCheck
public void do(){.....}
//注解只有一个参数为value的属性
@RoleCheck(1)
public void do(){.....}
//注解有一到多个属性
@RoleCheck(level=1,name="MS")
public void do(){.....}
看完以上的内容,咱们其实只是作了一件事,就是给不一样的物件贴上标签,可是只贴上标签,若是咱们不会根据标签进行处理的话,就毫无心义了,和注释毫无区别。
注解处理器就是咱们的处理环节,注解处理器能够在运行时经过反射机制读取到标签的信息从而进行处理。
一、首先能够经过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
二、而后经过 getAnnotation() 方法来获取 Annotation 对象。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是 getAnnotations() 方法。
public Annotation[] getAnnotations() {}
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的全部注解。
咱们作的事情是什么,经过class对象的 isAnnotationPresent()判断我Test类是否是有@RoleCheck注解,若是有的话就把这个注解的描述信息打印出来,这里打印出的是默认值。
@RoleCheck
public class Test {
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(RoleCheck.class);
if ( hasAnnotation ) {
RoleCheck testAnnotation = Test.class.getAnnotation(RoleCheck.class);
System.out.println("id:"+roleCheck.level());
}
}
}
上面的例子中,只是检阅出了注解在类上的注解,其实属性、方法上的注解照样是能够的。一样仍是基于反射。
//返回HelloController类中全部定义的方法
Method[] methods = HelloController.class.getDeclaredMethods();
//遍历每个方法
for(Method method:methods)
{
//对于标有注解,且名称为doSomething的方法进行处理
RoleCheck roleCheck =method.getAnnotation(RoleCheck.class);
if(roleCheck!=null&&method.getName().equals("doSomething"))
{
//..........
}
}
**********************************************************
//返回HelloController类中全部定义的字段
Field[] fields = HelloController.class.getDeclaredFields();
//遍历每个字段
for(Field field :fields)
{
RoleCheck roleCheck = field.getAnnotation(RoleCheck.class);
if(roleCheck!=null&&field.getName().equals("level"))
{
//.......
}
}
当开发者使用了Annotation 修饰了类、方法、Field 等成员以后,这些 Annotation 不会本身生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。咱们能够给本身答案了,注解有什么用?给谁用?给 编译器或者 APT 用。
好比举一个注解使用实例,JUNIT测试框架:
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
@Test 标记了要进行测试的方法 addition_isCorrect().
再举一个注解使用实例,SpringMVC
@RequestMapping(value = "/add.do")
public String addOrder(Order order) {
try {
orderService.add(order);
return "操做成功";
} catch (Exception e) {
e.printStackTrace();
return "操做失败,请重试";
}
}
@RequestMapping代表了要进行地址映射的方法。