注解在反射机制里的应用

注解
注解在开发中常被我们利用到反射机制中,辅助反射机制做更多灵活的操作
注解在如今JAVA流行的框架中被大量的应用,简化了以前繁琐的配置工作。

注解可以在:
类上,属性上,方法上,构造器上,以及参数上使用,即在方法的大括号里面不能使用。
可以通过java内置的注解@Target来说明当前注解可以被应用的位置,对应的值被定义在ElementType上
例如:
@Target(ElementType.TYPE)  注解只能被用于类上
@Target({ElementType.TYPE,ElementType.METHOD}) 注解只能被用于类上或方法上
当可以用于多个位置时,需要定义成数组的方式包含所有ElementType的值,即"{}"包含
@Retention注解,用于标注当前注解的保留级别,有三个选项

RetentionPolicy.SOURCE 注解仅保留在源代码中
RetentionPolicy.CLASS 注解保留在字节码中,但是反射机制不能调用
RetentionPolicy.RUNTIME 注解保留在字节码文件中,并且可以被反射机制所使用
当不指定@Retention时,默认的保留级别为CLASS,因此我们通常都需要明确指出保留级别为RUNTIME

设置注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunClass {

}
/**
 * 注解可以定义参数
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunMethod {
    /*
        定义参数的格式为:
        格式:类型 参数名() [default 默认值]
        注:default可选,用于为当前参数定义默认值。如果不指定,则使用注解时必须为此参数赋值。

        使用注解传参时格式:
        @注解名(参数名1=参数值1[,参数名2=参数值2,....])

        如果注解@AutoRunMethod只有一个参数,且参数名为num时,那么使用时格式如下:
        @AutoRunMethod(num=1)

        =============重点=============
        如果注解中只有一个参数,参数名建议选取value,这样的好处是,使用时可以不指定参数名,如:
        @AutoRunMethod(1)

        如果指定了默认值,则可以不指定参数,例如:
        @AutoRunMethod()   此时注解中参数的使用default的默认值

     */
    //为注解定义一个int型的参数
//    int num() default 1;//一个参数时,参数名不建议选取value以外的名字。
    int value() default 1;
}

将注释用在具体类里面:

@AutoRunClass
public class Person {
    private String name = "张三";
    private int age= 18;
    public Person(){

    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @AutoRunMethod(3)
    public void sayHello(){
        System.out.println(name+":Hello!");
    }

    @AutoRunMethod(5)
    public void sayHi(){
        System.out.println(name+":Hi");
    }

    @AutoRunMethod
    public  void watchTV(){
        System.out.println(name+":看电视");
    }
    public void sing(){
        System.out.println(name+"唱歌");
    }
    private void dosome(){
        System.out.println("我是Person的私有方法dosome()");
    }
    public  void doSomeThing(String something){
        System.out.println(name+"正在做"+something);
    }
    public void doSomeThing(String something,int count){
        for(int i=0;i<count;i++){
            System.out.println(name+"正在做"+something+i+"次");
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


@AutoRunClass
public class Student {
    @AutoRunMethod(7)
    public void study(){
        System.out.println("好好学习,天天向上");
    }
    public void playGame(){
        System.out.println("Student:玩游戏!");
    }
}

1、反射机制中查看注解:

public class ReflectDemo8 {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");

        //判断当前类对象所表示的类是否被注解@AutoRunClass标注了?
        boolean tf = cls.isAnnotationPresent(AutoRunClass.class);
        if(tf){
            System.out.println(cls.getName()+"被注解@AutoRunClass标注了!");
        } else {
            System.out.println(cls.getName()+"没有被注解@AutoRunClass标注了!");
        }
    }
}

2、方法上查看注解:

public class ReflectDemo9 {
    public static void main(String[] args) throws Exception{
        Class cls = Class.forName("reflect.Person");
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            /*
                除了类对象Class之外,像方法对象Method,属性对象Field等都有
                该方法,用于判断其表示的内容是否被某个注解标注了
             */
            if(method.isAnnotationPresent(AutoRunMethod.class)){
                System.out.println(method.getName()+":被注解@AutoRunMethod标注了");
            } else {
                System.out.println(method.getName()+":没有被注解@AutoRunMethod标注了");
            }
        }
    }
}

3、实例1,自动实例化与当前类Test3在同一个包中被@AutoRunClass标注的类。

public class Test3 {
    public static void main(String[] args) throws Exception {
        File dir = new File(
                Test3.class.getResource(".").toURI()
        );
        //通过当前类Test3的类对象获取所在的包名
        String packageName = Test3.class.getPackage().getName();
        //获取Test3.class文件所在的目录中所有.class文件
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs) {
            //获取字节码文件的文件名
            String fileName = sub.getName();
            String className = fileName.substring(0, fileName.indexOf("."));
            //加载该类的类对象
            Class cls = Class.forName(packageName + "." + className);
            if(cls.isAnnotationPresent(AutoRunClass.class)){
                System.out.println("实例化:"+className);
                Object o = cls.newInstance();
            }
        }
    }
}

4、实例2,自动调用与Test4在同一个包中那些被@AutoRunClass标注的类中所有被@AutoRunMethod标注的方法。

public class Test4 {
    public static void main(String[] args) throws Exception {
        File dir = new File(
                Test4.class.getResource(".").toURI()
        );
        //通过当前类Test3的类对象获取所在的包名
        String packageName = Test4.class.getPackage().getName();
        //获取Test3.class文件所在的目录中所有.class文件
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs) {
            //获取字节码文件的文件名
            String fileName = sub.getName();
            String className = fileName.substring(0, fileName.indexOf("."));
            //加载该类的类对象
            Class cls = Class.forName(packageName + "." + className);
            if(cls.isAnnotationPresent(AutoRunClass.class)){
                System.out.println("实例化:"+className);
                Object o = cls.newInstance();
                Method[] methods = cls.getDeclaredMethods();
                for(Method method : methods){
                    if(method.isAnnotationPresent(AutoRunMethod.class)){
                        System.out.println("调用了"+cls.getName()+"的"+method.getName()+"方法");
                        method.invoke(o);
                    }
                }
            }
        }
    }
}

5、在反射机制中获取注解的参数

public class ReflectDemo10 {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            //判断该方法是否被注解@AutoRunMethod标注了
            if(method.isAnnotationPresent(AutoRunMethod.class)){
                //通过方法对象获取该注解
                AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
                int value = arm.value();
                System.out.println(
                        "方法"+method.getName()+
                        "上的注解AutoRunMethod指定的参数值为:"+value
                );
            }
        }
    }
}

6、实例3, 自动调用与Test4在同一个包中那些被@AutoRunClass标注的类中所有被@AutoRunMethod标注的方法n次n对应的是注解@AutoRunMethod传入的参数值。

public class Test5 {
    public static void main(String[] args) throws Exception {
        File dir = new File(
                Test4.class.getResource(".").toURI()
        );
        //通过当前类Test3的类对象获取所在的包名
        String packageName = Test4.class.getPackage().getName();
        //获取Test3.class文件所在的目录中所有.class文件
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs) {
            //获取字节码文件的文件名
            String fileName = sub.getName();
            String className = fileName.substring(0, fileName.indexOf("."));
            //加载该类的类对象
            Class cls = Class.forName(packageName + "." + className);
            if(cls.isAnnotationPresent(AutoRunClass.class)){
                Object o = cls.newInstance();
                //获取该类定义的所有方法
                Method[] methods = cls.getDeclaredMethods();
                for(Method method : methods){

                    if(method.isAnnotationPresent(AutoRunMethod.class)){
                        AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
                        int value = arm.value();
                        System.out.println("自动调用"+className+"类的方法:"+method.getName()+"()"+value+"次");
                        for(int i=0;i<value;i++) {
                            method.invoke(o);
                        }
                    }
                }
            }
        }
    }
}

7、getDeclaredMethods方法的有参形式怎么传:

     File dir = new File(
                    DispatcherServlet.class.getClassLoader().getResource(
                            "./com/webserver/controller"
                    ).toURI()
            );
            File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
            for (File sub : subs) {
                String fileName = sub.getName();
                String className = fileName.substring(0, fileName.indexOf("."));
                Class cls = Class.forName("com.webserver.controller." + className);
                //判断该类是否被@Controller标注了
                if (cls.isAnnotationPresent(Controller.class)) {
                    Method[] methods = cls.getDeclaredMethods();
                    for (Method method : methods) {
                        //判断该方法是否被@RequestMapping标注了
                        if (method.isAnnotationPresent(RequestMapping.class)) {
                            //获取该注解
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            //获取该注解的参数(该方法处理的请求路径)
                            String value = rm.value();
                            if (path.equals(value)) {//判断当前请求是否为该方法处理的请求
                                //实例化该Controller
                                Object o = cls.newInstance();
                                //执行该方法
                                method.invoke(o, request, response);
                                return;
                            }
                        }
                    }
                }
            }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值