1. 反射的概念
将类的各个组成部分封装成其他对象,这就是反射机制。
Java代码的运行阶段
源代码阶段->Class对象阶段->运行阶段
图片来源 黑马Java零基础入门到就业_Java基础(IDEA版本)
将Person.class文件封装成Class对象的过程就是反射。
反射的好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的扩展性。
2. 获取Class对象的三种方式
Class.forName("类的全限定名") :将字节码文件加载到内存。类名.class :通过类名.属性 获取Class对象。对象名.getClass() :通过调用Object.getClass方法 获取Class对象。
package reflect_test;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass1 = Class.forName("reflect_test.Test");
Class<Test> testClass = Test.class;
Class<? extends Test> aClass = new Test().getClass();
System.out.println(aClass1.hashCode());
System.out.println(testClass.hashCode());
System.out.println(aClass.hashCode());
}
}
注: 同一个.class文件在程序运行中,只会被加载一次,堆中只有一个Class对象。
3. Class类的方法
获取字段
方法 | 作用 |
---|
public Field getField(String name) | 根据字段名获取public修饰的字段对象 | publice Field[] getFields() | 获取public修饰的字段对象 | publice Field getDeclaredField(String name) | 根据字段名获取字段对象 | publice Field[] getDeclaredFields() | 获取所有字段对象 |
Filed类的方法 | 作用 |
---|
publice set(Object obj,Object value) | 给obj对象的字段赋值 | publice get(Object obj) | 获取对象obj的字段值 | publice void setAccessible(boolean flag) | 不是公共的要开启暴力反射,才能获取、设置值 |
获取构造器
方法 | 作用 |
---|
publice Constructor getConstructor(Class<?>… parameterTypes) | 获取public修饰的构造器 | publice Constructor<?>[] getConstructors() | 获取所有public修饰的构造器 | publice Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 获取构造器 | publice Constructor<?>[] getDeclaredConstructors() | 获取所有构造器 |
Constructor类的方法 | 作用 |
---|
public T newInstance(Object … initargs) | 创建对象,也可以直接用Class对象.newInstance()方法创建对象 | public void setAccessible(boolean flag) | 开启暴力反射 |
获取方法
Method类的方法 | 作用 |
---|
public Method getMethod(String name, Class<?>… parameterTypes) | 获取public修饰的方法,参数是方法名,参数列表 | pulic Method[] getMethods() | 获取所有public方法 | public Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 获取方法,参数是方法名,参数列表 | public Method[] getDeclaredMethods() | 获取所有方法 |
Method类的方法 | 作用 |
---|
public Object invoke(Object obj, Object… args) | 执行ojb对象的方法,方法参数是args | public void setAccessible(boolean flag) | 开启暴力反射 |
4. 反射案例
使用反射创建任意对象,执行任意方法。
实现代码
package reflect_test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class CustomFramework {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Properties properties = new Properties();
properties.load(new FileInputStream("methods.properties"));
String className = properties.getProperty("className");
String method = properties.getProperty("method");
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();
Method m = clazz.getMethod(method);
m.invoke(o);
}
}
配置文件
className=reflect_test.Person
method=method
注: 不改代码,只改配置文件,更易扩展。许多框架的配置文件中使用全类名其实都是用的反射。
5. 参考资料
黑马Java零基础入门到就业_Java基础(IDEA版本)
|