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);

         

       

  • 相关阅读:
    宿主机无法访问CentOS7上Jenkins服务的解决办法
    415. Add Strings
    367. Valid Perfect Square
    326. Power of Three
    258. Add Digits
    231. Power of Two
    204. Count Primes
    202. Happy Number
    172. Factorial Trailing Zeroes
    171. Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/li3807/p/6765037.html
Copyright © 2011-2022 走看看