java_反射
什么是反射
概念
- 放射:将类的各个部分封装为其他对象,这就是反射机制。
java代码在内存中经历的三个阶段
1、 Source 源代码阶段
- 执行javac编译命令从.java文件到.class文件的过程都是在源代码阶段,.class字节码文件会将类分为多个部分,其中分为成员变量部分,成员方法部分,构造方法部分等。
2、 Class 类对象阶段
- 通过ClassLoader(类加载器)将字节码文件加载到内存中。
- 通过Class类对象来描述进入内存中的字节码文件的特征和行为。将成员变量、成员方法、构造方法等封装成单独的对象放入Class类对象中。
- 最后我们可以通过Class对象的一些行为创建具体的某个对象。
3、 runtime 运行时阶段
- new 类();
反射的好处
- 在程序的运行期间操作这些对象。
- 降低程序的耦合性,提高程序的可扩展性。
获取Class类对象的方法
- 获取class类对象的方式有三种,分别对应的java代码经历的三个阶段
1、 Class.forName("全类名");
- 将字节码文件加载进内存,返回class对象
- 多用于配置文件,将类名定义在配置文件中
2、 类名.class;
- 通过类名的属性class获取
- 多用于参数传递
3、 对象.getClass();
- getClass()方法是定义在Object类中的
多用于对象获取字节码
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次。
package top.uaoie.day03; import top.uaoie.domain.Person; public class ReflectDome01 { public static void main(String[] args) throws Exception { //1. Class.forName("全类名"); Class clazz1 = Class.forName("top.uaoie.domain.Person"); //2. 类名.class; Class clazz2 = Person.class; //3. 对象.getClass(); Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz1); System.out.println(clazz2); System.out.println(clazz3); //比较三个对象 System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); } }
反射的应用
1、 获取所有的成员变量
- Field[] getFields()
- Field getFied(String name)
- Field[] getDeclaredFields()
- Field getDeclaredFied(String name)
2、 获取所有的构造方法
- Constructor<?>[] getConstructors()
- Constructor
getConstructors(类<?>... parameterTypes) - Constructor<?>[] getDeclaredConstructors()
- Constructor
getDeclaredConstructors(类<?>... parameterTypes)
3、 获取所有的成员方法
- Method[] getMethods()
- Menthod getMethod(String name,类<?>...parameterTypes)
- Method[] getDeclaredMethods()
- Menthod getDeclaredMethod(String name,类<?>...parameterTypes)
4、 获取类名
- String getName()
以下为演示通过反射获取所有的成员变量
- 创建一个名为Person的类,里面的代码如下:
package top.uaoie.domain; public class Person { public String a; protected String b; String c; private String d; @Override public String toString() { return "Person{" + "a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } }
- 再新建一个名为ReflectDome02的类,里面的代码如下:
package top.uaoie.day03; import top.uaoie.domain.Person; import java.lang.reflect.Field; public class ReflectDome02 { public static void main(String[] args) throws Exception { //获取Person的Class对象,此处是在阶段二部分获取的 //也可在第一阶段获取,如:Class.forName("top.uaoie.domain.Person"); Class p = Person.class; //获取成员变量 Field[] fields = p.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("---------------------"); Field a = p.getField("a"); System.out.println(a); //创建一个对象 Person person = new Person(); //获取成员变量a的值 Object value = a.get(person); System.out.println(value); //设置成员变量a的值 a.set(person, "这是a的值"); System.out.println(person); System.out.println("================="); Field[] declaredFields = p.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } Field d = p.getDeclaredField("d"); //忽略访问权限修饰符 d.setAccessible(true);//暴力反射 Object value2 = d.get(person); System.out.println(value2); } }
小结
- 获取类的class对象有多种方法,其中使用Class.forName可以通过读取配置文件获取全类名
- Class.forName和getField等类是代码会报错是因为传入的是字符串,所有可能不存在这个类获或者方法,所以需要处理异常
- 通过反射可以直接访问到任何成员变量名,不受访问修饰符的限制
- 可以setAccessible设置为true来暴力反射获取或者更改成员变量的值
来源:https://www.cnblogs.com/Juaoie/p/12355337.html