• 反射+注解_笔记


    一、反射

    1. 定义

       将类的各个组成部分封装成对象,这就是反射机制

       三个步骤:source源代码阶段类加载器——Class类对象阶段创建对象——Runtime运行时阶段

      

      2.获取class对象的方式

       ⑴class.forName("全类名") :将字节码文件加载进内存,返回class对象

        多用于配置文件,将类名定义在配置文件中,读取文件,加载

       ⑵类名.class :通过类名的属性class获取

        多用于参数的传递

       ⑶对象.getClass() :getClass方法在object类中定义着

        多用于对象的获取字节码的方式

      *在同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过那种方式获得的class对象都是同一个。

      3. 获取功能

       ⑴获取成员变量们

        File[]   getFields()   : 获取所有public修饰的成员变量  

        File   getField(String name) :获取指定名称的public修饰 的成员变量

        File[]   getDeclaredFields()   : 获取所有的成员变量,不考虑修饰符

        File   getDeclaredField(String name) :获取指定名称的成员变量,不考虑修饰符

        Filed:成员变量操作      

            暴力反射 d.setAccessible(true)

            设置值: void set(Object obj,object value)

            获取值:get(Object  obj)

              ⑵ 获取构造方法们

        Constructor<?>[]    getDeclaredConstructors()

        Constructor<T>    getDeclaredConstructor(类<?>.... parameterTypes)//(string.class,int.class)

        Constructor:构造方法

            创建对象 newInstance(object..initargs)//(张三,18)

                 如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法

       ⑶获取成员方法们

        Method[]  getDeclaredMethods()

        Method getDeclaredMethod(String name,类<?>... parameterTypes)

        Method方法对象

            执行方法,object invoke(object obj ,object...args)

            获取方法名:String getName 

       ⑷获取类名

        String geiName()

     4.“框架测试 ”

      public class Test {
         public static void main(String[] args) throws Exception {
            //可以创建任意类的对象,可以执行任意方法

            /*
                前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
             */
           /*  Person p = new Person();
              p.eat();*/
            /*
            Student stu = new Student();
            stu.sleep();*/


            //1.加载配置文件
            //1.1创建Properties对象
            Properties pro = new Properties();
            //1.2加载配置文件,转换为一个集合
            //1.2.1获取class目录下的配置文件
            ClassLoader classLoader = ReflectTest.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("pro.properties");
            pro.load(is);

            //2.获取配置文件中定义的数据
            String className = pro.getProperty("className");
            String methodName = pro.getProperty("methodName");


            //3.加载该类进内存
            Class cls = Class.forName(className);
            //4.创建对象
            Object obj = cls.newInstance();
            //5.获取方法对象
            Method method = cls.getMethod(methodName);
            //6.执行方法
            method.invoke(obj);
             }
       }

      ----------------------------------------------------------------------------

      //pro.properties

      className=cn.itcast.domain.Student
      methodName=sleep

    二、注解

      1.概念: 说明程序的,给计算机看的,元数据,是对包,类,方法等元素的说明

          javadoc

          @注解名称

          @param 参数

          @return 返回值

      2.作用分类

       @编写文档:通过代码里标注的注解文档【生成doc文档】   

       @代码分析:通过代码里标注的注解对代码进行分析【使用反射】

       @编译检查: 通过代码里标注的注解让编译器能够实现基本的编译检查【override】

      3.JDK 预定义注解

        @override  检测该注解标注的方法是否是继承父类接口的

        @Deprecated  该注解标注的内容,表示已过时

        @suppressWarnings  压制警告的

       4.自定义注解(javap  反编译)

       格式: 

          元注解

          public @interface 注解名称{

            属性列表

            }

       本质:注解是一个接口,该接口默认继承Annotation接口

          public interface MyAnno extends java.lang.annotation.Annotation

       属性:接口中可以定义的成员方法

           要求:

              1.属性的返回值类型(只有基本数据类型,String,枚举,注解以上类型的数组)

              2.在使用的时候必须要赋值,(default 默认赋值,如果只有一个属性需要赋值且名字为VALUE,则赋值可以省略VALUE)

              @MyAnno(value=12,per=Person.p1,anno2=@MyAnno2,str={'a','b'})

        元注解:用于描述注解的注解

             @Target:描述注解能够作用的位置

                  TYPE:作用于类上

                  METHOD:可以作用于方法上

                  FIELD:可以作用于成员变量上

             @Retention:描述注解被保留的阶段

               SOURCE 

               CLASS

               RUNTIME:RetentionPolicy.Runtime

             @Documented:描述注解是否被抽取到api文档中

             @inherited:描述注解是否被子类继承

         5.在程序中使用(解析)注解:获取注解中定义的属性值

         .1获取注解定义的位置的对象(class,method,filed)

         .2获取指定的注解

           getAnnotation(class) 

         .3调用注解中抽象方法获取配置的属性值

        @Pro(className = "cn.itcast.annotation.Demo1",methodName = "show")
        public class ReflectTest {
              public static void main(String[] args) throws Exception {

              /*
                  前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
               */
              //1.解析注解
              //1.1获取该类的字节码文件对象
              Class<ReflectTest> reflectTestClass = ReflectTest.class;
              //2.获取上边的注解对象
              //其实就是在内存中生成了一个该注解接口的子类实现对象
              /*
                  public class ProImpl implements Pro{
                      public String className(){
                          return "cn.itcast.annotation.Demo1";
                      }
                      public String methodName(){
                          return "show";
                      }
                  }
         */
              Pro an = reflectTestClass.getAnnotation(Pro.class);
              //3.调用注解对象中定义的抽象方法,获取返回值
              String className = an.className();
              String methodName = an.methodName();
              System.out.println(className);
              System.out.println(methodName);

              //3.加载该类进内存
              Class cls = Class.forName(className);
              //4.创建对象
              Object obj = cls.newInstance();
              //5.获取方法对象
              Method method = cls.getMethod(methodName);
              //6.执行方法
              method.invoke(obj);
            }
        }

      6.注解小案例

       /*简单的测试框架

       * 当主方法执行后,会自动自行被检测的的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中去。

         public class TestCheck{

          //1.创建计算器对象

          Calculator c=new Calculator();

          //2. 获取字节码文件对象

          Class cls=c.getClass();

          //3.获取所有方法

          Method [] methods=cls.getMethods();

          int number =0;//出现异常的次数

          BufferedWreiter bw=new BufferedWriter(new FileWriter("bug.txt"));

          for (Method method: Methods){

            //4.判断方法上是否有Check注解

            if(method.isAnnotationPresent(check.class)){

             //5.有,执行

              try{

                 method.invoke();

              }catch(Exception e){

               //6.捕获异常

               //记录到文件中 

                 number++;

                  bw,wite(method.getName() +"方法出异常了");

                  bw.newLine();

                  bw.write("异常的名称"+e.getCause().getClass().getSimpleName());

                  bw.newLine();

                  bw.write("异常的原因"+e.getCause().getMessage());                    

                  bw.newLine();

               }

            }

            bw.wrtie(“本次测试一共出现”+number+“异常”);

            bw.flush();

            bw.close();

          }   

        }

       

             

        

  • 相关阅读:
    第4天:Ansible模块
    第3天:YAML语法
    使用EXtjs6.2构建web项目
    Node中的定时器详解
    java中使用MD5加密技术
    Node+Socketio实现消息群发功能
    Angularjs+node+Mysql实现地图上特定点的定位以及附加信息展示
    那些年构建SSH所遇到的坑
    浅谈时间复杂度与空间复杂度
    创建视图并删除相关表中的记录
  • 原文地址:https://www.cnblogs.com/ironman-yan/p/11817016.html
Copyright © 2020-2023  润新知