1.概念:
运行时,对任意类,都能知道这个类的所有属性和方法;对任意一对象,都能够调用它的每个方法和属性;这种动态获取、动态调用的功能称为Java语言的反射机制。
2.实现
Java反射相关的API在包java.lang.reflect中
Member接口 | 该接口可以获取有关类成员(域或者方法)后者构造函数的信息。 |
AccessibleObject类 | 该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。 |
Array类 | 该类提供动态地生成和访问JAVA数组的方法。 |
Constructor类 | 提供一个类的构造函数的信息以及访问类的构造函数的接口。 |
Field类 | 提供一个类的域的信息以及访问类的域的接口。 |
Method类 | 提供一个类的方法的信息以及访问类的方法的接口。 |
Modifier类 | 提供了 static 方法和常量,对类和成员访问修饰符进行解码。 |
Proxy类 | 提供动态地生成代理类和类实例的静态方法。 |
1)获取类的Class对象
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。获取类的Class对象有多种方式(此处以Boolean类为例):
调用getClass | Boolean var1 = true; Class<?> classType2 = var1.getClass(); System.out.println(classType2); 输出:class java.lang.Boolean |
运用.class 语法 | Class<?> classType4 = Boolean.class; System.out.println(classType4); 输出:class java.lang.Boolean |
运用静态方法 Class.forName() | Class<?> classType5 = Class.forName("java.lang.Boolean"); System.out.println(classType5); 输出:class java.lang.Boolean |
运用primitive wrapper classes的TYPE 语法 这里返回的是原生类型,和Boolean.class返回的不同 | Class<?> classType3 = Boolean.TYPE; System.out.println(classType3); 输出:boo |
2)获取类的Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA 的Class<T>类提供了几个方法获取类的属性
public Field getField(Stringname) | 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段 |
public Field[] getFields() | 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段 |
public FieldgetDeclaredField(Stringname) | 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 |
public Field[] getDeclaredFields() | 返回 |
3)获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法。Class<T>类提供了几个方法获取类的方法。
public MethodgetMethod(String name,Class<?>... parameterTypes) | 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法 |
public Method[] getMethods() | 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口 包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法 |
public Method getDeclaredMethod(Stringname,Class<?>... parameterTypes) | 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法 |
public Method[] getDeclaredMethods() | 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法, 包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 |
4)获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例。Class<T>类提供了几个方法获取类的构造器。
public Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法 |
public Constructor<?>[] getConstructors() | 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法 |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法 |
public Constructor<?>[] getDeclaredConstructors() | 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 它们是公共、保护、默认(包)访问和私有构造方法 |
5)新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建
调用无自变量ctor | 1、调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败. Class<?> classType = ExtendType.class; Object inst = classType.newInstance(); System.out.println(inst); 输出: Type:Default Constructor ExtendType:Default Constructor
2、调用默认Constructor对象的newInstance方法 Class<?> classType = ExtendType.class; Constructor<?> constructor1 = classType.getConstructor(); Object inst = constructor1.newInstance(); System.out.println(inst); 输出: Type:Default Constructor ExtendType:Default Constructor com.quincy.ExtendType@1006d75 |
调用带参数ctor | 3、调用带参数Constructor对象的newInstance方法 Constructor<?> constructor2 = classType.getDeclaredConstructor(int.class, String.class); Object inst = constructor2.newInstance(1, "123"); System.out.println(inst); 输出: Type:Default Constructor ExtendType:Constructor with parameters com.quincy.ExtendType@15e83f9 |
6)调用类的函数
通过反射获取类Method对象,调用Field的Invoke方法调用函数。
通过反射获取类的Field对象,调用Field方法设置或获取值
3.代码
Java反射机制主要提供了以下功能:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
1) 得到某个对象的属性
public Object getProperty(Object owner, String fieldName) throws Exception { Class ownerClass = owner.getClass(); Field field = ownerClass.getField(fieldName); Object property = field.get(owner); return property; }
2) 得到某个类的静态属性
public Object getStaticProperty(String className, String fieldName) throws Exception { Class ownerClass = Class.forName(className); Field field = ownerClass.getField(fieldName); Object property = field.get(ownerClass); return property; }
3)执行某对象的方法
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception { Class ownerClass = owner.getClass(); Class[] argsClass = new Class[args.length]; for (int i = 0, j = args.length; i < j; i++) { argsClass[i] = args[i].getClass(); } Method method = ownerClass.getMethod(methodName, argsClass); return method.invoke(owner, args); }
4) 执行某个类的静态方法
public Object invokeStaticMethod(String className, String methodName,Object[] args) throws Exception { Class ownerClass = Class.forName(className); Class[] argsClass = new Class[args.length]; for (int i = 0, j = args.length; i < j; i++) { argsClass[i] = args[i].getClass(); } Method method = ownerClass.getMethod(methodName, argsClass); return method.invoke(null, args); }
基本的原理和实例3相同,不同点是最后一行,invoke的一个参数是null,因为这是静态方法,不需要借助实例运行。
5) 新建实例
public Object newInstance(String className, Object[] args) throws Exception { Class newoneClass = Class.forName(className); Class[] argsClass = new Class[args.length]; for (int i = 0, j = args.length; i < j; i++) { argsClass[i] = args[i].getClass(); } Constructor cons = newoneClass.getConstructor(argsClass); return cons.newInstance(args); }
这里说的方法是执行带参数的构造函数来新建实例的方法。如果不需要参数,可以直接使用newoneClass.newInstance()来实现。
6)判断是否为某个类的实例
public boolean isInstance(Object obj, Class cls) { return cls.isInstance(obj); }
7)得到数组中的某个元素
public Object getByArray(Object array, int index) { return Array.get(array,index); }