注解(Annotation) 为我们在代码中天界信息提供了一种形式化的方法,是我们可以在稍后
某个时刻方便地使用这些数据(通过 解析注解 来使用这些数据)。
现在我们开始研究怎么使用自定义注解,从而了解注解是怎么工作的。
定义一个注解 MyAnnotationClassDefinition.java
package org.lsy.test.little;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotationClassDefinition {
public String classExplanation();
public String classEessage();
//也可以给一个默认值,如下
//public String classExplanation() default "";
}
要注意的是注解定义的形式是@interface,它本身也需要注解,而且是不可缺少的。
其中主要的2个是:@Target , @Retention
作用是;
@Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括:
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
@Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
还有
@Documented 将此注解包含在 javadoc 中
@Inherited 允许子类继承父类中的注解
上面的注解只能用在类上面,
我们再定义一个可以用在方法上的。
MyAnnotationDefinition,java
package org.lsy.test.little;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotationDefinition {
public String explanation();
public String message();
}
写一个很普通的类:OneClass.java
注意,要使用注解
package org.lsy.test.little;
@MyAnnotationClassDefinition(classExplanation="我是类OneClass的classExplanation",classEessage="我是类OneClass的classEessage")
public class OneClass {
@MyAnnotationDefinition(explanation="我是方法printMyMessageOne的explanation",
message="我是方法printMyMessageOne的message")
public void printMyMessageOne(){
}
@MyAnnotationDefinition(explanation="我是方法printMyMessageTwo的explanation",
message="我是方法printMyMessageTwo的message")
public void printMyMessageTwo(){
}
}
再写一个main函数运行一下,看看效果
package org.lsy.test.little;
import java.lang.annotation.*;
import java.lang.reflect.Method;
public class MyAnnotationTest {
public static void main(String[] args) {
OneClass one=new OneClass();
if(OneClass.class.isAnnotationPresent(MyAnnotationClassDefinition.class)){
MyAnnotationClassDefinition myAnnotationClassDefinition=
(MyAnnotationClassDefinition)OneClass.class.getAnnotation(MyAnnotationClassDefinition.class);
System.out.println("类OneClass使用注解MyAnnotationClassDefinition,其属性classExplanation是:"
+myAnnotationClassDefinition.classExplanation());
System.out.println("类OneClass使用注解MyAnnotationClassDefinition,其属性classEessage是:"
+myAnnotationClassDefinition.classEessage());
}else{
System.out.println("类OneClass没有注解MyAnnotationDefinition");
}
//
Method[] methods = OneClass.class.getDeclaredMethods();
for (Method method : methods) {
// 判断方法中是否有指定注解类型的注解
boolean hasAnnotation = method.isAnnotationPresent(MyAnnotationDefinition.class);
if (hasAnnotation) {
//根据注解类型返回方法的指定类型注解
MyAnnotationDefinition myannotation = method.getAnnotation(MyAnnotationDefinition.class);
System.out.println("MyAnnotationDefinition( explanation = "+
myannotation.explanation() + " , message = "
+ myannotation.message() + " )");
}
}
}
}
控制台打印:
类OneClass使用注解MyAnnotationClassDefinition,其属性classExplanation是:我是类OneClass的classExplanation
类OneClass使用注解MyAnnotationClassDefinition,其属性classEessage是:我是类OneClass的classEessage
MyAnnotationDefinition( explanation = 我是方法printMyMessageOne的explanation , message = 我是方法printMyMessageOne的message )
MyAnnotationDefinition( explanation = 我是方法printMyMessageTwo的explanation , message = 我是方法printMyMessageTwo的message )
由此,我们可以想到spring使用注解的原理也不外乎如此。
它先读取你的注解,然后根据读取的值去xml中寻找。
如果找到了就实例化一个对象返回。这样据实现了注入的效果。