# 简介

反射是 Java 的特征之一。通过反射可以获得并调用任意一个类的所有属性和方法。反射可以在运行期间动态地创造对象、调用方法。

# 反射的主要使用

反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(例如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。

反射是框架实现的灵魂

# 优缺点

  • 优点:代码实现灵活、为各种框架的功能实现提供便利。
  • 缺点:

    • 滥用反射会额外消耗系统资源。
    • 反射会忽略权限检查,增加安全问题。

      # 基本用法

      TargetObject 为例: ```java public class TargetObject { private String value;

      public TargetObject(String value) { this.value = value; }

      public TargetObject() { value = “value”; }

      public void publicMethod(String s) { System.out.println(“I love “ + s); }

      private void privateMethod() { System.out.println(“value is “ + value); }

}

  1. <a name="OBWrK"></a>
  2. ## | 获得 Class 的方式
  3. 1. 通过`Class.forName()`传入类的全路径获取:
  4. ```java
  5. public static Class<?> forName(String className)
  6. // xx.xxxx.TargetObject:类的全路径
  7. Class alunbarClass1 = Class.forName("xx.xxxxx.TargetObject");
  1. 通过具体类的 class 属性获取:

    1. Class alunbarClass2 = TartgetObject.class;
  2. 通过实例对象的instance.getClass()获取:

    1. TargetObject o = new TargetObject();
    2. Class alunbarClass3 = o.getClass();
  3. 通过类加载器xxxClassLoader.loadClass()传入类路径获取:

    1. Class clazz = ClassLoader.loadClass("xx.xxxx.TargetObject");

    通过类加载器获取 Class 对象不会进行初始化,静态代码和静态对象不会得到执行。

    | 创建实例对象

  4. 通过 Class 对象的newInstance()方法创建 Class 实例对象 ```java /**

  • 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例 */ Class<?> targetClass = TargetObject.class; TargetObject targetObject = (TargetObject) targetClass.newInstance(); ```
  1. 通过创建 Class 对象的构造器对象,再调用构造器对象的newInstance()方法来创建实例,即用制定的构造器来创建对象。 ```java /**
  • 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例 */ Class<?> targetClass = TargetObject.class; Constructor<?> constructor = targetClass.getConstructor(String.class); TargetObject targetObject2 = (TargetObject) constructor.newInstance(“value”); ```

    | 方法获取及调用

  • getDeclaredMethods():返回类或者接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但是不包括继承的方法。
  • getMethods():返回某个类的所有公共方法,包括继承类的公用方法。
  • getDeclaredMethod():返回类的一个特定的方法,其中第一个参数为方法的名称,后面的参数为方法的参数对应的Class对象。
  • 得到的方法通过invoke()进行调用。 ```java public Method[] getDeclaredMethods() throws SecurityException

public Method[] getMethods() throws SecurityException

public Method getDeclaredMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

  1. ```java
  2. /**
  3. * 获取 TargetObject 类中定义的所有方法
  4. */
  5. Method[] methods = targetClass.getDeclaredMethods();
  6. for (Method method : methods) {
  7. System.out.println(method.getName());
  8. }
  9. /**
  10. * 获取指定方法并调用
  11. */
  12. Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class);
  13. publicMethod.invoke(targetObject, "new value");
  14. /**
  15. * 调用 private 方法
  16. */
  17. Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
  18. // 取消安全检查
  19. privateMethod.setAccessible(true);
  20. privateMethod.invoke(targetObject);

| 成员变量的获取

  • getField():所有的公有变量信息。
  • getDeclaredField():所有已声明的成员变量,但是不能得到父类的成员变量。

    1. /*
    2. 获取指定参数并对参数进行修改
    3. */
    4. Field field = targetClass.getDeclaredField("value");
    5. // 取消安全检查
    6. field.setAccessible(true);
    7. field.set(targetObject, "new new value");

    # 利用反射创造数组

    利用反射创建数组的例子如下:

    1. public static void testArray() throws ClassNotFoundException {
    2. Class<?> cls = Class.forName("java.lang.String");
    3. Object array = Array.newInstance(cls,25);
    4. //往数组里添加内容
    5. Array.set(array,0,"hello");
    6. Array.set(array,1,"Java");
    7. Array.set(array,2,"fuck");
    8. Array.set(array,3,"Scala");
    9. Array.set(array,4,"Clojure");
    10. //获取某一项的内容
    11. System.out.println(Array.get(array,3));
    12. }

    其中的 Array 类为 java.lang.reflect.Array 类,通过 Array.newInstance() 创建数组对象。

    # 参考

  1. 深入解析Java反射(1) - 基础