前几天学了注解,说一下我对注解处理器的认识吧,我觉得注解处理器可以用于生成新的类来完成某些功能,但是不能直接修改当前的类.。
生成注解处理器需要我们自定义注解,然后将注解标注在类的某些方法或属性上,在利用反射技术提取注解的信息,是否含有该注解,或者有哪些注解,我们再编写代码将我们得到的信息根据需求实现相应的功能,比如提取公共方法生成一个新的接口或类,等等。
生成注解处理器有可以是通过反射,也可以用提供的apt实现。在这里我向大家展示存反射技术实现一个提取指定类的方法,生成一个接口的思路。
四大元注解和自定义注解我就不多说了。首先我们需要知道,如果自定义注解需要在运行时使用反射来处理时,那么该注解的@Retention注解一定要是RetentionPolicy.RUNTIME,因为反射是在JVM运行时来进行处理的。
1.首先我们说一说获得类的注解的信息
先自定义一个注解,这个注解可以注释在类和属性上
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Label {
String name() default "";
}
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface wish {
boolean can() default false;
int value() default -1;
}
再定义用注解标注类的一个类
@Label(name = "Demo")
public class Demo {
@Label(name = "名字")
private String name;
@wish(can = true,value = 5)
@Label(name = "年龄")
private int age;
@wish(value = 30,can = true)
@Label(name = "价格")
private double price;
@Label(name = "描述")
private String des;
@wish
public void cry(){
System.out.println("嗷呜");
}
public String eat(){
return "好吃";
}
@wish
public void sleep(int time){
System.out.println("睡了8个小时");
}
}
现在我们开始演示如何利用反射获取一个类的注解的信息
首先得到该类的CLass对象,再获取这个类的属性和方法
Class<Demo> demoClass = Demo.class;
我们可以通过getAnnotations()来获取标注该类的所有注解,指的是写在class Demo{头上的所有注解。返回有个注解数组,再for循环得到每一个注解
Class<Demo> demoClass = Demo.class;
//得到该标注类的注解信息
Annotation[] annotations = demoClass.getAnnotations();
//我们循环打印看看
for (Annotation annotation : annotations) {
System.out.println("注解:"+annotation.toString());
}
得到:
注解:@annotate.Label(name=Demo)
Demo只被Labal注解标注,有一个变量name,这个值为"Demo"。注解的属性也叫做成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
Class<? extends Annotation> aClass = annotation.getClass();
System.out.println("获取该注解的所有方法:");
//得到注解所有方法,打印方法名
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
method.setAccessible(true);
System.out.println(method.getName());
}
System.out.println("获取该注解的所有属性:");
//得到注解所有属性,打印属性名
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
System.out.println(field.getName());
}
得到结果:
获取该注解的所有方法method:
name
equals
toString
hashCode
annotationType
获取该注解的所有属性field:
m1
m3
m2
m4
m0
说明这是注解的属性就是我们类中的方法。我们可以通过注解的对象annotation.方法名()得到方法的返回值,也就是我们设置的值,注解属性对应的值。最后打印的m0到m4是什么我也不知道,有兴趣的可以去探索一下。
获取注解对象也可以通过 :
aClass.getAnnotation(注解名.class) 获取指定注解
下面我们演示一下获取类的指定注解对象以及注解的属性的值
Label annotation = demoClass.getAnnotation(Label.class);
String name = annotation.name();
System.out.println(name);
打印得到:Demo
类的说完了,属性和方法的注解信息获取方法也讲完了,和类基本上一样,属性是filed.getAnnotation....方法是method.getAnnotation
//演示属性获取注解
Field[] fields = demoClass.getDeclaredFields();
for (Field field : fields) {//得到每一个属性
field.setAccessible(true);
String fieldName = field.getName();//得到属性名
System.out.println("属性名:"+fieldName+"该属性注解:");
Annotation[] annotations = field.getAnnotations();//获取属性的所有注解
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
System.out.println("-----------------");
}
下面我们得到结果:
属性名:name该属性注解:
@annotate.Label(name=名字)
-----------------
属性名:age该属性注解:
@annotate.wish(value=5, can=true)
@annotate.Label(name=年龄)
-----------------
属性名:price该属性注解:
@annotate.wish(value=30, can=true)
@annotate.Label(name=价格)
-----------------
属性名:des该属性注解:
@annotate.Label(name=描述)
-----------------
方法的我就不写了,一模一样。
2.再说说怎么提取一个类的指定方法生成接口
- 我们通过编写一个指定的注解@A
- 让该注解标记上我们要提取的方法:
- 得到该类的Class对象,遍历所有方法,找到含有该注解的方法,我们得到这个方法的所以信息:修饰符,返回类型,方法名,参数列表[参数类型 ,参数名]
- 我们先遍历这个类的所有方法
- 每一个方法通过getAnnotations()得到所有注解,返回注解数组
- 遍历上述的注解数组,取出每一个注解对象annotation
- annotaion.annotationType().equals(A.class) ,annotationType()得到注解类型对象,如果annotaion是A注解类型,就返回true
- 如果你想获得注解属性的信息,就强制转化,A aAn = (A)annotation,然后就可以调用A注解的属性类,aAn.属性名(),你也可以进行其他额外的操作,得到更多的信息,比如该方法的返回类型,方法名等等。
第二步,标记就如下:
@A
public void fun1(){}
对于第三步,我就上面的Demo类做一个演示,假设我要提取的方法为被注解wish标记了的方法,有cry方法和sleep方法.
Class<Demo> demoClass = Demo.class;
//演示获得被@wish注解标注的方法,并打印出来
Method[] methods = demoClass.getDeclaredMethods();
//遍历所有方法
for (Method method : methods) {
method.setAccessible(true);
//获取每一个方法的所有注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {//遍历
if (annotation.annotationType().equals(wish.class)) {//如果该注解是wish注解
//定义buffer来接收保存每一个方法信息
StringBuffer buffer = new StringBuffer();
//强制转化
wish wish = (wish) annotation;
//得到注解属性
boolean can = wish.can();
int value = wish.value();
//得到注解名
String annotationName = annotation.annotationType().getSimpleName();
buffer.append("@" + annotationName + "(value = " + value + " , can= " + can + ")\n");
//得到方法的信息
//得到方法修饰符
int modifiers = method.getModifiers();
String modifier = Modifier.toString(modifiers);
//得到方法返回类型的名字,getName()得到全路径:包名.类型名 ;getSimpleName()得到类型名
String returnTypeName = method.getReturnType().getSimpleName();
//得到方法名
String methodName = method.getName();
//得到参数列表
Parameter[] parameters = method.getParameters();
buffer.append(modifier + " " + returnTypeName + " " + methodName + " (");
for (Parameter parameter : parameters) {//遍历参数列表
//得到参数列表
String parameterTypeName = parameter.getType().getSimpleName();
//得到参数名字
String parameterName = parameter.getName();
buffer.append(parameterTypeName + " " + parameterName + ",");
}
//如果右参数,则最后多了一个","号,我们现在要去掉
if (parameters.length > 0)
buffer = new StringBuffer(buffer.substring(0, buffer.length() - 1));
buffer.append("){ }");
//打印含有wish注解的方法
System.out.println(buffer+"\n");
}
}
}
得到结果如下:
@wish(value = -1 , can= false)
public void sleep (int time){ }@wish(value = -1 , can= false)
public void cry (){ }
进程已结束,退出代码为 0
好了,这个我就将完了,生成接口的基本问题都已经清理,没有思路的话就看看我前面的利用反射为一个只含有setter和getter普通方法的Person类生成一个MyPerson.java文件。之前没做,现在自己动手打一遍,对反射更加熟练了,动态之美。_璃431的博客-CSDN博客y
由于时间关系,先暂时写这么点吧,还有一些内容我后面会补上来的。