zoukankan      html  css  js  c++  java
  • 笔记:反射

    反射库提供了大量操作Java代码的工具集,以便编写能够通道操作Java代码的程序,能够分析类能力的程序称为反射(reflective)。

    1. Class

      在程序运行期间,Java运行时系统始终为所有的对象维护一个称为运行时的类型标识,这个信息跟踪着每个对象所属的类,虚拟机利用运行时类型信息选择相应的方法执行,可以通过专门的类来访问这些信息,保存这些信息的类被称为 Class,Object 类的getClass方法将返回一个Class类型的实例,示例代码如下:

            public static void main( String[] args )

              {

                      String str = "测试号";

                      Class stringClassObj = str.getClass();

                        

                      System.out.println("Str Class is "+stringClassObj.getName());

              }

      可以调用静态方法 forName 获得类名对应得Class对象,示例代码如下:

      String className = "java.util.Date";

      Class cl = Class.forName(className);

      虚拟机为每个类型管理一个Class对象,因此可以利用 == 运算符实现两个类对象得比较操作,还可以使用 newInstance 方法调用默认的构造函数初始化新创建的对象,示例代码如下:

      if(stringClassObj.getClass() == String.getClass()){

          ...

      }

         

      String className = "java.util.Date";

      Object m = Class.forName(className).newInstance();

      如果没有默认的构造函数,则调用类对象的 newInstance 会抛出异常,如果希望调用构造函数来创建实例,则必须使用 Constructor类的 newInstance 方法。

    2. 利用反射分析类的能力

      在Java的 java.lang.reflect包中有三个类 Field、Method和Constructor类,分别用于描述类的域、方法和构造器,三个类都有一个叫做getName的方法,用来返回项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象;Method Constructor类有能够报告参数类型的方法,Method类还有一个可以报告返回类型的方法,这三个类都有getModifiers的方法,返回一个整数值,用不同的位开关描述public static 这样的修饰符,通过 Modifier类的 isPublic、isPrivate isFinal 来判断方法的修饰符。

      Class类中的 getFields、getMethods和getConstructors 方法分别返回类提供的 public 域、方法和构造器;getDeclareFields、getDeclareMethods getDeclaredConstructors 方法将分别返回类中声明的全部域、方法和构造器,其中包括私有、保护成员,但不包括超类(基类)的成员,示例代码如下:

      public class App {

          public static void main(String[] args) {

              Class clazz = Double.class;

              Field[] fields = clazz.getFields();

              Method[] methods = clazz.getMethods();

              String clazzDeclare = BuildClassCode(clazz);

              System.out.println(clazzDeclare);

              System.out.println("{");

              for (Field f : fields) {

                  System.out.println(" " + BuildFieldCode(f));

              }

         

              System.out.println("");

              for (Method m : methods) {

                  System.out.println(" " + BuildMethodCode(m));

              }

              System.out.println("}");

          }

         

          /**

           * 构建类源码

           * @param clazz

           * @return

           */

          protected static <T> String BuildClassCode(Class<T> clazz) {

              StringBuilder sb = new StringBuilder();

               int modifiers = clazz.getModifiers();

               sb.append(Modifier.toString(modifiers) + " ");

               sb.append(clazz.getSimpleName() + " ");

                

               Class superClass = clazz.getSuperclass();

               if (superClass != null && superClass != Object.class) {

                   sb.append("extends " + superClass.getSimpleName());

               }

                

               Class[] superInterfaces = clazz.getInterfaces();

               if (superInterfaces != null && superInterfaces.length > 0) {

                   sb.append(" implements ");

                

                   for (int j = 0; j < superInterfaces.length; j++) {

                       sb.append(superInterfaces[j].getName());

                

                       if (j != superInterfaces.length - 1) {

                           sb.append(", ");

                       }

                   }

               }        

                     return sb.toString();

          }

         

          /**

           * 构建公共字段域代码

           * @param field

           * @return

           */

          protected static String BuildFieldCode(Field field) {

              StringBuilder sb = new StringBuilder();

         

              int mod = field.getModifiers();

              sb.append(Modifier.toString(mod) + " ");

              sb.append(field.getType().getSimpleName() + " " + field.getName() + ";");

         

              return sb.toString();

          }

         

          /**

           * 构建公共方法代码

           * @param method

           * @return

           */

          protected static String BuildMethodCode(Method method) {

              StringBuilder sb = new StringBuilder();

         

              int mod = method.getModifiers();

              sb.append(Modifier.toString(mod) + " ");

              sb.append(method.getReturnType().getSimpleName() + " " + method.getName());

              sb.append("(");

              Class[] parameterTypes = method.getParameterTypes();

              for (int i = 0; i < parameterTypes.length; i++) {

                  Class c = parameterTypes[i];

                  sb.append(c.getName());

         

                  if (i != parameterTypes.length - 1) {

                      sb.append(", ");

                  }

              }

              sb.append(")");

         

              return sb.toString();

          }

      }

    3. 在运行时使用反射分析对象

      查看对象域的关键方法是Field类中的get方法,如果 f 是一个Field类型的对象,obj是某个包含 f 域的类对象,f.get(obj)将返回一个对象,其值为obj域的当前值,如果访问的时私有域,get方法的调用将抛出一个 IllegalAccessException 异常,反射机制默认行为受限与Java的访问控制,如果需要覆盖Java的访问控制,可以调用Field、Method和Constructor对象的setAccessible方法,示例代码如下:

              Employee em = new Employee();

              em.setName("lixue");

              em.setYear(1982);

              em.setMonth(12);

              em.setDay(7);

                

              Field nameField = em.getClass().getDeclaredField("name");

              // 覆盖访问控制,允许访问私有字段域

              nameField.setAccessible(true);

                

              Object val = nameField.get(em);

              System.out.println("Employee name is "+val);

    4. 使用反射编写泛型数组代码

      可以使用Array类的newInstance方法构造新数组,调用他必须提供二个参数,一个时数组的元素类型,一个是数组的长度,示例代码如下:

      Object newArray = Array.newInstance(componentType,newLength);

    5. 调用任意方法

      在Method类中有一个invoke方法,他允许调用包装在当前Method对象中的方法,invoke的方法签名是:

      Object invoke(Object obj,Object... args)

      第一个参数是隐式参数,其余的对象提供了显示参数,对于静态方法,第一个参数可以被忽略,可以设置为 null,示例代码如下:

              Method getNameMethod = em.getClass().getDeclaredMethod("getName", null);

              String nameValue = (String) getNameMethod.invoke(em);

              System.out.println("Employee name is "+nameValue);

         

       

  • 相关阅读:
    Django U2 模型
    Django U0 使用Django
    Django H2 文档查看
    python模块--time模块/os模块/sys模块
    python模块-logging和collections以及random模块
    python-hashlib模块configparser模块logging模块
    python模块--序列化
    python面向对象的特殊方法和单例模式
    python类属性和类方法以及静态方法和反射
    python面向对象的三个特性
  • 原文地址:https://www.cnblogs.com/li3807/p/6765037.html
Copyright © 2011-2022 走看看