反射获取自定义注解的信息,生成注解处理器

前几天学了注解,说一下我对注解处理器的认识吧,我觉得注解处理器可以用于生成新的类来完成某些功能,但是不能直接修改当前的类.。

生成注解处理器需要我们自定义注解,然后将注解标注在类的某些方法或属性上,在利用反射技术提取注解的信息,是否含有该注解,或者有哪些注解,我们再编写代码将我们得到的信息根据需求实现相应的功能,比如提取公共方法生成一个新的接口或类,等等。

生成注解处理器有可以是通过反射,也可以用提供的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.再说说怎么提取一个类的指定方法生成接口

  1. 我们通过编写一个指定的注解@A
  2. 让该注解标记上我们要提取的方法:
  3. 得到该类的Class对象,遍历所有方法,找到含有该注解的方法,我们得到这个方法的所以信息:修饰符,返回类型,方法名,参数列表[参数类型 ,参数名]
    1. 我们先遍历这个类的所有方法
    2. 每一个方法通过getAnnotations()得到所有注解,返回注解数组
    3. 遍历上述的注解数组,取出每一个注解对象annotation
    4. annotaion.annotationType().equals(A.class) ,annotationType()得到注解类型对象,如果annotaion是A注解类型,就返回true
    5. 如果你想获得注解属性的信息,就强制转化,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

 由于时间关系,先暂时写这么点吧,还有一些内容我后面会补上来的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luncker(摆烂版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值