Java反射
1. 类的加载
- 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
- 加载
- 指将class文件读入内存,并为之创建一个Class对象。
- 任何类被使用时系统都会建立一个Class对象。
- 连接
- 验证 - 是否有正确的内部结构,并和其他类协调一致。
- 准备 - 负责为类的静态成员分配内存,并设置默认初始化值。
- 解析 - 将类的二进制数据中的符号引用替换为直接引用。
- 初始化
- 加载
2. 类的初始化时机
- 创建类的实例
- 类的静态变量,或者为静态变量赋值
- 类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
3. 三种类的加载器
- 负责将.class文件加载到内存中,并为之生成对应的Class对象。
- Bootstrap ClassLoader 根类加载器
- 也被称为引导类加载器,负责Java核心类的加载
- 比如System, String等。在JDK中JRE的lib目录下rt.jar文件中
- Extension ClassLoader 扩展类加载器
- 负责JRE的扩展目录中jar包的加载。
- 在JDK中JRE的lib目录下ext目录
- System ClassLoader 系统类加载器
- 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
- Bootstrap ClassLoader 根类加载器
4. 反射的概念及作用
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
5. class文件的产生过程
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
6. 获取class文件对象的三种方式
- 通过Object类中的getObject()方法
Test t = new Test(); Class c = t.getClass();
- 通过 类名.class 获取到字节码文件对象(任意数据类型都具备一个class静态属性)
Class c = Test.getClass();
- 通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName)。
Class c3 = Class.forName("com.ccblogs.reflect.Test");
- 三种方法的区别:
- 前两种你必须明确Person类型。
- 第三种是指定这种类型的字符串,按照配置文件加载。
7. 反射获取空参构造方法并运行
-
ComboListTest.java文件
import java.lang.reflect.Constructor; public class ComboListTest { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); // 获取class文件对象中所有公共的构造方法 Constructor[] cons = c.getConstructors(); for (Constructor con : cons) { System.out.println(con); } // 运行类中的空参构造方法 Constructor con = c.getConstructor(); Object obj = con.newInstance(); System.out.println(obj); } }
-
ComboList.java文件
public class ComboList { public ComboList() { System.out.println("无参构造方法"); } public ComboList(String str, int iNum) { System.out.println("有参构造方法:" + str + ", " + iNum); } private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
8. 反射获取有参数构造方法并运行
- ComboListTest.java文件
import java.lang.reflect.Constructor; public class ComboListTest { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); // 获取class文件对象中有参构造方法并运行 Constructor con = c.getConstructor(String.class, int.class); con.newInstance("11", 2); } }
- ComboList.java文件
public class ComboList { public ComboList() { System.out.println("无参构造方法"); } public ComboList(String str, int iNum) { System.out.println("有参构造方法:" + str + ", " + iNum); } private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
9. 反射获取构造方法并运行的快速方法
- ComboListTest.java文件
public class ComboListTest { @SuppressWarnings({ "rawtypes" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); // Class类中定义方法,T newInstance()直接创建被反射类的对象实例 // 快捷方式获取无参构造函数,被反射的类必须有无参构造函数,且该构造函数是public Object obj = c.newInstance(); System.out.println(obj); } }
- ComboList.java文件
public class ComboList { public ComboList() { System.out.println("无参构造方法"); } public ComboList(String str, int iNum) { System.out.println("有参构造方法:" + str + ", " + iNum); } private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
10. 反射获取私有构造方法并运行
推荐,破坏封装性和安全性。
- ComboList.java文件
public class ComboList { public ComboList() { System.out.println("无参构造方法"); } public ComboList(String str, int iNum) { System.out.println("有参构造方法:" + str + ", " + iNum); } @SuppressWarnings("unused") private ComboList(int iNum, String str) { } private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
- ComboListTest.java文件
import java.lang.reflect.Constructor; public class ComboListTest { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); Constructor con = c.getDeclaredConstructor(int.class, String.class); con.setAccessible(true); Object obj = con.newInstance(12, "34"); System.out.println(obj); } }
11. 反射获取成员变量并改值
- ComboList.java文件
public class ComboList { public ComboList() { System.out.println("无参构造方法"); } public ComboList(String str, int iNum) { System.out.println("有参构造方法:" + str + ", " + iNum); } @SuppressWarnings("unused") private ComboList(int iNum, String str) { } public String key; public String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
- ComboListTest.java文件
import java.lang.reflect.Constructor; public class ComboListTest { @SuppressWarnings({ "rawtypes" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); Field field = c.getField("key"); Object obj = c.newInstance(); field.set(obj, "keyId"); System.out.println(obj); } }
12. 反射获取空参数成员方法并运行
- ComboList.java文件
public class ComboList { public void setKey() { System.out.println("setKey********"); } public void setValue(String value) { System.out.println("setValue********" + value); } }
- ComboListTest.java文件
import java.lang.reflect.Method; public class ComboListTest { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); Object obj = c.newInstance(); Method method = c.getMethod("setKey"); method.invoke(obj); } }
13. 反射获取有参数的成员方法并运行
- ComboList.java文件
public class ComboList { public void setKey() { System.out.println("setKey********"); } public void setValue(String value) { System.out.println("setValue********" + value); } }
- ComboListTest.java文件
import java.lang.reflect.Method; public class ComboListTest { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) throws Exception { Class c = Class.forName("com.ccblogs.inflect.ComboList"); Object obj = c.newInstance(); Method method = c.getMethod("setValue", String.class); method.invoke(obj, "kkkkkkkkkkkkk"); } }
14. 反射泛型擦除
- ComboListTest.java文件
import java.lang.reflect.Method; import java.util.ArrayList; public class ComboListTest { @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) throws Exception { ArrayList<String> arrayList = new ArrayList<String>(); arrayList.add("a"); Class c = arrayList.getClass(); Method method = c.getMethod("add", Object.class); method.invoke(arrayList, 1); method.invoke(arrayList, 2); System.out.println(arrayList); } }
15. 反射通过配置文件运行
- 工程下创建文件Config.properties
className=com.ccblogs.inflect.ComboList methodName=setValue
- ComboList.java文件
public class ComboList { public void setKey() { System.out.println("setKey********"); } public void setValue(String value) { System.out.println("setValue********" + value); } }
- ComboListTest.java文件
import java.io.FileReader; import java.lang.reflect.Method; import java.util.Properties; public class ComboListTest { @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) throws Exception { FileReader fr = new FileReader("Config.properties"); Properties pr = new Properties(); pr.load(fr); fr.close(); String className = pr.getProperty("className"); String methodName = pr.getProperty("methodName"); Class c = Class.forName(className); Object obj = c.newInstance(); Method method = c.getMethod(methodName, String.class); method.invoke(obj, "123"); } }