1.注解是什么
注解(Annotation)也叫元数据,是JDK5.0引入的一种注释机制,用于对代码进行配置说明,可以对包,类,接口,字段,方法参数,局部变量等进行使用。
一般注解可以划分为以下三类:
- 元注解: 元注解使用与定义注解的注解,包含@Retention(标明注解被保留的阶段),@Target(标明注解使用的范围),@Inherit额的(标明注解可继承),@Documented(标明是否生成javadoc文档)
- java自带的标注注解:包含开发人员常见的@OverRide(标明重写某个方法),@Deprecated(标明某个类或方法已经过时),@SuppressWarning(标明要忽略的警告),使用这些注解这些注解后编译器就会进行检查
- 自定义注解:按照注解的需求结合元注解定义新注解
2.注解的作用
在介绍注解(Annotation)的作用之前我们先介绍下xml,在注解引入之前,xml被广泛的应用于描述元数据,然而随着代码的增加,并且由于xml并没有和代码紧密的耦合在一起,xml的维护变得越来越复杂,此时注解(Annotation)被创造出来,通过使用注解,代码和元数据配置紧密的耦合在了一起,代码维护被简化
3.注解的原理
(01) @interface
使用 @interface 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。
定义 Annotation 时,@interface 是必须的。
注意:它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。
(02) @Documented
类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。
定义 Annotation 时,@Documented 可有可无;若没有定义,则 Annotation 不会出现在 javadoc 中。
(03) @Target(ElementType.TYPE)
前面我们说过,ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。
@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着,MyAnnotation1 是来修饰"类、接口(包括注释类型)或枚举声明"的注解。
定义 Annotation 时,@Target 可有可无。若有 @Target,则该 Annotation 只能用于它所指定的地方;若没有 @Target,则该 Annotation 可以用于任何地方。
(04) @Retention(RetentionPolicy.RUNTIME)
前面我们说过,RetentionPolicy 是 Annotation 的策略属性,而 @Retention 的作用,就是指定 Annotation 的策略属性。
@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。
定义 Annotation 时,@Retention 可有可无。若没有 @Retention,则默认是 RetentionPolicy.CLASS。
4.注解的使用
package com.annotation.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) //Type表示该注解作用于普通类,接口类,或枚举
@Retention(RetentionPolicy.RUNTIME) //注解会被编译器记录在类文件中,在运行时由虚拟机保留,因此可以通过反射读取到它们
public @interface MyClassAnnotation { //自定义作用于类的注解
String value() default "";
String[] classAnnoFunc() default {};
}
package com.annotation.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) //Feild 表示作用于字段声明(包括枚举常量)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFieldAnnotation {
String value() default "";
String[] fieldAnnoFunc() default {};
}
package com.annotation.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //@Target可有可无,如果没有添加Target则表示该注解可以使用在任何地方
@Retention(RetentionPolicy.RUNTIME)//@Retention可有可无,如果没有则默认为Retentionpolicy.CLASS
public @interface MyMethodAnnotation {
String value() default "";
String[] methodAnnoFunc() default {};
}
package com.annotation.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER) //参数声明
@Retention(RetentionPolicy.RUNTIME)
public @interface MyParamAnnotation {
String value() default "";
}
package com.annotation.test;
@MyClassAnnotation(value = "classValue", classAnnoFunc = "")
public class MyAnnotationTest {
@MyFieldAnnotation
public String testField;
@MyMethodAnnotation(methodAnnoFunc = "testAnnotation")
public String testFunction(@MyParamAnnotation("paramValue")String param) {
return param;
}
}
package com.annotation.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class MainTest {
public static void main(String[] args) throws ClassNotFoundException {
//通过字节码获取对象
Class<?> aClass = MyAnnotationTest.class;
//通过Class.forName 获取对象
Class<?> bClass = Class.forName("com.annotation.test.MyAnnotationTest");
//通过getClass获取对象
Class<?> cClass = new MyAnnotationTest().getClass();
//查看该类是否存在自定义的注解
boolean classFlag = bClass.isAnnotationPresent(MyClassAnnotation.class);
if(classFlag) {
Annotation[] annotations = bClass.getAnnotations();
for(Annotation anno : annotations) {
System.out.println(aClass.getName() + " --- " + ((MyClassAnnotation) anno).value() );
System.out.println(aClass.getName() + " --- " + ((MyClassAnnotation) anno).classAnnoFunc() );
}
}
System.out.println("---------------");
//通过反射获取该对象的所有方法
Method[] methods = bClass.getMethods();
for(Method m : methods) {
//遍历方法里面是否存在该自定义的注解
boolean methodFlag = m.isAnnotationPresent(MyMethodAnnotation.class);
//分析注解里面的参数
if(methodFlag) {
MyMethodAnnotation methodAnnotation = m.getAnnotation(MyMethodAnnotation.class);
System.out.println(m.getName() + " : " + methodAnnotation);
}else {
System.out.println(m.getName() + " 该方法未曾使用到注解");
}
//通过反射获取该方法的所有参数
Parameter[] parameters = m.getParameters();
for(Parameter param : parameters) {
boolean paramFlag = param.isAnnotationPresent(MyParamAnnotation.class);
if(paramFlag) {
MyParamAnnotation annotation = param.getAnnotation(MyParamAnnotation.class);
System.out.println(m.getName() + " : --- " + annotation.value());
}
}
}
System.out.println("---------------");
//通过反射获取对象的所有属性
Field[] fields = bClass.getFields();
for(Field f : fields) {
//查看属性上面是否存在改自定义的注解
boolean fieldFlag = f.isAnnotationPresent(MyFieldAnnotation.class);
//分析注解里面的参数
if(fieldFlag) {
MyFieldAnnotation fieldAnnotation = f.getAnnotation(MyFieldAnnotation.class);
System.out.println(f.getName() + " : " + fieldAnnotation);
}else {
System.out.println(f.getName() + " : " + "该属性未曾使用到注解");
}
}
}
}