# 简介
反射是 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); }
}
<a name="OBWrK"></a>## | 获得 Class 的方式1. 通过`Class.forName()`传入类的全路径获取:```javapublic static Class<?> forName(String className)// xx.xxxx.TargetObject:类的全路径Class alunbarClass1 = Class.forName("xx.xxxxx.TargetObject");
通过具体类的 class 属性获取:
Class alunbarClass2 = TartgetObject.class;
通过实例对象的
instance.getClass()获取:TargetObject o = new TargetObject();Class alunbarClass3 = o.getClass();
通过类加载器
xxxClassLoader.loadClass()传入类路径获取:Class clazz = ClassLoader.loadClass("xx.xxxx.TargetObject");
通过类加载器获取 Class 对象不会进行初始化,静态代码和静态对象不会得到执行。
| 创建实例对象
通过 Class 对象的
newInstance()方法创建 Class 实例对象 ```java /**
- 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例 */ Class<?> targetClass = TargetObject.class; TargetObject targetObject = (TargetObject) targetClass.newInstance(); ```
- 通过创建 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
```java/*** 获取 TargetObject 类中定义的所有方法*/Method[] methods = targetClass.getDeclaredMethods();for (Method method : methods) {System.out.println(method.getName());}/*** 获取指定方法并调用*/Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class);publicMethod.invoke(targetObject, "new value");/*** 调用 private 方法*/Method privateMethod = targetClass.getDeclaredMethod("privateMethod");// 取消安全检查privateMethod.setAccessible(true);privateMethod.invoke(targetObject);
| 成员变量的获取
getField():所有的公有变量信息。getDeclaredField():所有已声明的成员变量,但是不能得到父类的成员变量。/*获取指定参数并对参数进行修改*/Field field = targetClass.getDeclaredField("value");// 取消安全检查field.setAccessible(true);field.set(targetObject, "new new value");
# 利用反射创造数组
利用反射创建数组的例子如下:
public static void testArray() throws ClassNotFoundException {Class<?> cls = Class.forName("java.lang.String");Object array = Array.newInstance(cls,25);//往数组里添加内容Array.set(array,0,"hello");Array.set(array,1,"Java");Array.set(array,2,"fuck");Array.set(array,3,"Scala");Array.set(array,4,"Clojure");//获取某一项的内容System.out.println(Array.get(array,3));}
其中的 Array 类为 java.lang.reflect.Array 类,通过 Array.newInstance() 创建数组对象。
# 参考
