注解(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中寻找。
如果找到了就实例化一个对象返回。这样据实现了注入的效果。