创建第一个评论
package com.tmser.annotation;
public @interface TestA {
//这里定义了空注释,可以做什么呢? 我也不知道,他能用。
}
在以下步骤中使用。
package com.tmser.annotation;
import java.util.HashMap;
import java.util.Map;
使用了@TestA //类注释
公共类用户身份验证{
@TestA //使用了类成员的注释
私有整合者;
@TestA //使用了构建方法注释
公共用户身份验证
}
使用了@TestA //类方法的注释
公共void a () {
@TestA //使用了局部变量注释
mapm=newHashmap(0;
}
使用了公共void b (@ testaintegera )//方法参数注释
}
}
编译没有错误,ok,注释实验完成。 这个注释也太简单了吧。 好像传达不了任何信息。 不要着急。 接下来一步一步完善它,4位注释也开始按顺序出现。
4个meta评论分别为@Target,@Retention,@Documented,@Inherited,meta评论由java API提供,再次强调是专门用于评论定义的评论
@Target表示使用注释的位置。 枚举类ElemenetType中提供了可能的值,其中包括:
elemenettype.constructor------构造函数声明
包括elemenettype.field------域声明----- enum实例
elemenettype.local _ variable------局部变量声明
elemenettype.method----方法声明
elemenettype.package---- -包声明
elemenettype.parameter---- -参数声明
elemenettype.type------类、接口-----包含注释类型-----或enum声明
@Retention表示在哪个级别保存此注释信息。 枚举类型RetentionPolicy具有以下可选参数值:
retentionpolicy.source---------注释将被编译器丢弃
retention policy.class-------- -注释可以在class文件中使用,但在VM中会被丢弃
retentionpolicy.runtimevm----为了在运行时也保留注释,反射机制可以读取注释信息。
@Documented将此注释包含在javadoc中。 这表示javadoc工具将此注释提取到文档中。 doc文档的内容取决于此注释的内容。 相当于@see,@param等。
@Inherited允许子类从父类继承注释。
学习高骥远是最重要的。 最重要的是实践。 一个一个地实验一下吧。
第一个是@Target,给之前我们写的评论加元评论。
package com.tmser.annotation;
import Java.lang.annotation.element type;
import Java.lang.annotation.target;
@Target(elementtype.package ) /与前面定义的评论的不同之处在于,这里使用了元评论target
public @interface TestA {
}
ctrl s保存,今天的电脑比较给力,我们测试班很快出现了很多错误。 班级注释除外。 想到这个,聪明的你马上就理解了这个元评论的意思。 是不是理所当然地懈怠了? 有事故吗? 细心的朋友应该注意到,我们的测试类少了一个ElemenetType.PACKAGE属性,没有用。 在我们的评论中添加了这个属性的元评论后,我们测试程序的元评论都战死了。 不,我没有再加一个。 请追加。 package包,想成为
然是加载 package 前面。即@TestA package com.tmser.annotation;
什么也报错。这就搞不明白了,不加在这加哪去呢。我也不知道了,不过这是编译错误,我们的eclipse 将错误给我们指出了,就是Package annotations must be in file package-info.java ,e 文虽然不好,但这个简单的还是难不倒几个人的,package 注解必须定义在 package-info.java 中。package-info 又是什么东西,好了为节省你们的时间帮你百度好了(在另一篇我的另一篇博文里面,自己找吧,咔咔)。ok,到此 target 元注解就全部完成了。
第二个元注解: @Retention 参数 RetentionPolicy。有了前面的经验这个注解理解起来就简单多了,并且幸运的是这个注解还没有特殊的属性值。 简单演示下如何使用:
package com.tmser.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
}
第三和第四个元注解就不再举例了。比较简单,也没有值,相信看过上面的解释也就清楚了。下面我们还是继续来深入的探讨下注解的使用。上面的例子都非常简单,注解连属性都没有。ok,下面我们就来定义一个有属性的注解,并在例子程序中获取都注解中定义的值。
开始之前将下定义属性的规则:
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
代码:
@Target({TYPE,METHOD,FIELD,CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
String name();
int id() default 0;
Class gid();
}
下面改下我们的测试类:
package com.tmser.annotation;
import java.util.HashMap;
import java.util.Map;
@TestA(name="type",gid=Long.class) //类成员注解
public class UserAnnotation {
@TestA(name="param",id=1,gid=Long.class) //类成员注解
private Integer age;
@TestA (name="construct",id=2,gid=Long.class)//构造方法注解
public UserAnnotation(){
}
@TestA(name="public method",id=3,gid=Long.class) //类方法注解
public void a(){
Map m = new HashMap(0);
}
@TestA(name="protected method",id=4,gid=Long.class) //类方法注解
protected void b(){
Map m = new HashMap(0);
}
@TestA(name="private method",id=5,gid=Long.class) //类方法注解
private void c(){
Map m = new HashMap(0);
}
public void b(Integer a){
}
}
下面到了最重要的一步了,就是如何读取我们在类中定义的注解。只要读取出来了使用的话就简单了。
package com.tmser.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ParseAnnotation {
public static void parseTypeAnnotation() throws ClassNotFoundException {
Class clazz = Class.forName("com.tmser.annotation.UserAnnotation");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
TestA testA = (TestA)annotation;
System.out.println("id= ""+testA.id()+""; name= ""+testA.name()+""; gid = "+testA.gid());
}
}
public static void parseMethodAnnotation(){
Method[] methods = UserAnnotation.class.getDeclaredMethods();
for (Method method : methods) {
boolean hasAnnotation = method.isAnnotationPresent(TestA.class);
if (hasAnnotation) {
TestA annotation = method.getAnnotation(TestA.class);
System.out.println("method = " + method.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= "+annotation.gid());
}
}
}
public static void parseConstructAnnotation(){
Constructor[] constructors = UserAnnotation.class.getConstructors();
for (Constructor constructor : constructors) {
boolean hasAnnotation = constructor.isAnnotationPresent(TestA.class);
if (hasAnnotation) {
TestA annotation =(TestA) constructor.getAnnotation(TestA.class);
System.out.println("constructor = " + constructor.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= "+annotation.gid());
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
parseMethodAnnotation();
parseConstructAnnotation();
}
}
先别说话,运行:
id= "0"; name= "type"; gid = class java.lang.Long
method = c ; id = 5 ; description = private method; gid= class java.lang.Long
method = a ; id = 3 ; description = public method; gid= class java.lang.Long
method = b ; id = 4 ; description = protected method; gid= class java.lang.Long
constructor = com.tmser.annotation.UserAnnotation ; id = 2 ; description = construct; gid= class java.lang.Long
看到了吧,我们定义的注解都完整的输出了,你要使用哪个,直接拿去用就好了。
为了不让这篇文章打开太慢,我省略了类属性注解,及参数注解的解析。其实都大同小异。
另外,我也没有举使用例子。因为我认为好的教程是讲的详细的同时,还会留有扩展。如果我全部写出来,而你只是学习的话,那基本不会自己去动脑了,而是复制粘贴运行一遍完事。
最后提醒下:
1. 要用好注解,必须熟悉java 的反射机制,从上面的例子可以看出,注解的解析完全依赖于反射。
2. 不要滥用注解。平常我们编程过程很少接触和使用注解,只有做设计,且不想让设计有过多的配置时