java annotation详解
摘要
java annotation是jdk1.5引入的一种注解机制,记录一下注解的官方含义注解的定义
Annotations,a form of metadata,provide data about a program that is not part of the program
itself.Annotations have no direct effect on the operation of code they annotate
介绍中有一个关键词metadata,我们理解为元数据,那元数据我们怎么理解呢,其实就是描述数据的数据,java中以对象为基本,描述一个事物我们都喜欢把其抽象为一个对象,但是我们用什么样的数据去描述对象呢,因为对象本身也是一个数据,我倾向于把注解比喻为一个商品的标签,标签上可能记录的是该商品的元数据,比如价格,货号等,但是提供的信息却不是这个商品本身,就算把标签拿去也是不影响这个商品的使用。这样理解也是契合了官方介绍下的定义,就像反射的含义一样,把java类中的各种成分映射成响应的类,注解其实也是对于java类中的各个成分的一个标签。
常见的注解
@ Override
public String toString(){
return "this is String";
}
我们平时的代码编写中,@Override注解随处可见,可以尝试一些就算我把toString方法上的注解删除掉,代码也是可以运行的没有任何的问题,那思考一下那这个注解有什么用呢?我们上面把注解理解为商标,其实这个注解就是告诉编译器,这是一个方法,什么样的方法呢,是一个加了标签的方法,什么标签呢,一个加了重写标签的代码,并且编译器还可以发出错误,当他父类没有这个方法的时候,当可能我手滑了,toString写成toSString(),如果我没有加这个注解,其实是一帆风顺的,但是后面得到的情况就和我想要的不一样了。
为什么要引入注解
了解了一下jdk为何需要引入注解的历史,在注解以前,xml这种数据结构可能被广泛应用与元数据的描述,但是在某个特定的时期,一些开发人员觉得xml维护很麻烦,他们需要一种可以和代码更加密切的东西而不是xml有时可能和代码完全分开,有兴趣可以google一下xml vs annntations,但是注解就一定会比xml更好吗?其实也需要分场景,对于项目中的一些环境变量和参数,其实可以使用xml,可以和代码完成的区分开,但是如果你想修饰一些方法,类可能注解是更好的选择,所以我想这也是spring支持注解+xml两种方式的原因吧。
java中的注解组成
java annotation组成
- Annotation.java
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
- ElementType.java
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
- RetentionPolicy.java
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
说明:
(01)、我们可以把RetentionPolicy理解为有效的时间,我们可以查一下定义,分析一下这个枚举的三个元素的意思:
1、SOURCE:表明此种类型的注解仅存在与编译期间,编译完成以后这个注解就没有用了,根本都到不了字节码这个级别,比如我们常见的@Override,其实也就是在编译的时候判断该注解标记的方法是否父类有这个方法。
2、CLASS:仅存在类加载期间,类加载完成这个注解就没什么用了,这是一个默认值
3、RUNTIME:不会存在没用的情况,直接会将Annotation存储在class文件中,并且可由JVM读入,也是我们定义自定义注解选择的方式。
所以对于这三个关键组成,一个注解必须绑定一个RetentionPolicy和多个ElementType。
java提供的注解(以下4个注解只能标注在Annotaion类型上,也就是这四个注解只能标注注解)
-
@Documented 所标注的内容,会出现在javadoc中
-
@Retention 该注解是标注注解的RetentionPolicy
-
@Target 该注解是标注注解的ElementType
-
@Inherited 它所标记的注解具有继承的属性
-
@Override 只能标示在方法上,表明该方法是其父类方法的重写
-
@ Deprecated 所标注的内容,表明不被建议使用
-
@ SuppressWarnings 所标注的内容产生的警告,编译器可以忽略
-
@interface 定义一个Annotation类型,但是注意的是和interface是不同的,被标记以后,该注解就不能继承其他的注解或接口了。
注解的使用场景
1、编译检查
自定义注解 IDE提示.png
如图所示,重写toString()方法但是没有添加@Override注解,IDE会提醒。
2、在反射中使用Annotation
如果我们使用过java的反射代码,我们可以在代码中看到反射提供的类,方法和属性字段都有一个共同的方法getAnnotation()来返回注解对象。
使用demo
Class businessLogicClass = BusinessLogic.class;
for(Method method : businessLogicClass.getMethods()) {
Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " + todoAnnotation.author());
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" Status : " + todoAnnotation.status());
}
}
3、使用Annotation生成文档
使用@Documented会生成文档。
4、帮助查询代码
通过部分注解我们可以知道更容易知道方法之间的关系。
自定义注解
但是我们在一些开源框架中会经常看到一些框架中自定义的注解,比如我们常用的spring框架等,@Controller,@RequestMapping等,我们可以根据java原生的注解实现我们自定义的注解。
//实现用户的自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ToDO {
public enum level{LOW,MEDIUM,High}
public enum state{stared,finished}
String author() default "pjw";
level level() default level.LOW;
state state() default state.stared;
}
@ToDO(level = ToDO.level.MEDIUM,author = "pjq",state = ToDO.state.finished)
public static String getString(){
return "";
}
总结
其实我们可以把注解理解成一个特殊的java类,其实我们会发现注解可以干的事情配置文件也是可以干的,在实际我们的编程中,其实注解和配置文件是携同工作的,只是使用场景哪一种更为合适,仅此而已。