反射
-
类加载和类加载器
类加载:java文件会首先被编译成class文件,class文件被jvm加载进内存并初始化数据就叫做类加载。
类加载器:类加载器就是jvm中的一个程序,负责加载class等文件进内存。加载我们程序中的类进内存的类加载器是AppClassLoader -
反射的概念
class文件加载进内存之后会产生一个Class对象,反射就是要求我们通过Class对象操作类的成员变量、构造方法、成员方法。 -
反射的实现思路
第一步:获取Class对象(有三种方式)
-
通过类名.class获取: Class c=Student.class;
-
通过对象.getClass(); Class c=student.getClass();
-
使用Class的静态forName()方法获取; Class<?> c=Class.forName(“包名.类名”);
总结:一个类只有一个Class对象,任何方式得到的Class对象都是同一个。
补充:通过Class对象的newInstance方法也可以创建出这个类的对象。默认执行的是public修饰的空参构造
-
第二步:通过Class对象获取构造方法对象、成员变量对象、成员方法对象(都有4个方法)
规律:方法带s表示获取多个对象,不带s表示获取指定的一个对象。带Declared获取任意修饰符修饰的对象,不带Declared表示只能获取
public修饰的对象。
获取构造方法对象:
Constructor<?>[] getConstructors():
返回所有public修饰的构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()
返回所有任意修饰符修饰的构造方法对象的数组
Constructor getConstructor(Class<?>... parameterTypes):
返回单个public修饰的构造方法对象,该方法的参数是构造方法中参数的Class对象,例如:String.class,int.class
Constructor getDeclaredConstructor(Class<?>... parameterTypes):
返回单个任意修饰符修饰的构造方法对象
获取成员变量对象:
Field[] getFields():
返回所有public修饰的成员变量对象的数组
Field[] getDeclaredFields():
返回所有任意修饰符修饰的成员变量对象的数组
Field getField(String name):
返回单个public修饰的成员变量对象,参数是成员变量的名称
Field getDeclaredField(String name):
返回单个任意修饰符修饰的成员变量对象,参数是成员变量的名称
获取成员方法对象:
Method[] getMethods():
返回所有的public修饰的成员方法对象的数组,包括继承的。
Method[] getDeclaredMethods()
//返回所有任意修饰符修饰的成员方法对象的数组,不包括继承的。
Method getMethod(String name, Class<?>... parameterTypes)
//根据方法名称和参数类型或者单个public修饰的成员方法对象
Method getDeclaredMethod(String name,Class<?>... parameterTypes)
:根据方法名称和参数类型或者单个任意修饰符修饰的成员方法对象
第三步:操作构造方法对象、成员变量对象、成员方法对象。
操纵构造方法对象:创建对象
T newInstance(Object... initargs)
:创建一个类的对象,参数是构造方法需要的值
注意:如果构造方法是非public修饰的,那么在实例化对象之前需要使用setAccessible(true)取消检查,也叫暴力访问。
操作成员变量对象:
void set(Object obj, Object value)
:给obj对象的Field成本变量设置值为value
Object get(Object obj)
:获取Obj对象的Field成员变量的值并返回。
注意:如果成员变量是非public修饰的,那么在调用set/get方法之前需要使用setAccessible(true)取消检查,也叫暴力访问。
操作成员方法对象:调用方法
Object invoke(Object obj, Object... args)
:调用obj对象的method对应的方法,传递的参数是args,返回值是Object类型。
注意:如果成员方法是非public修饰的,那么在调用invoke方法之前需要使用setAccessible(true)取消检查,也叫暴力访问。
案例
实现将map集合中的数据封装到标准java类对应的属性身上
package com.jxufe_ldl.homework_01.test02;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
// 通过反射java类Field和Method方式完成数据封装
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
// 定义Map集合,并给Map集合添加元素
Map<String, Object> map=new HashMap<String, Object>();
map.put("name","zhangsan");
map.put("age",18);
map.put("sex","男");
// 调用populate()方法
Person p = new Person();
mypopulate(p, map);
System.out.println(p);
}
// 实现将map集合中的数据封装到标准java类对应的属性身上
public static <E,T> void mypopulate(Object obj, Map<E,T> map) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
// 获取对象的 Class 对象
Class<?> c = obj.getClass();
// 获取对象的 成员变量 和 成员set方法
Field[] fields = c.getDeclaredFields();
Method[] methods = c.getDeclaredMethods();
Set<E> keySet = map.keySet();
for (E key : keySet) {
for (Field field : fields) {
T value = map.get(key);
// String key1 = String.valueOf(key);
// String field1 = String.valueOf(field);
String str = String.valueOf(field.getName());
if (str.equals(key)) {
// 获取对应的成员方法
// str.substring(0, 1).toUpperCase()+str.substring(1);
Method setField = c.getDeclaredMethod("set"+ str.substring(0, 1).toUpperCase()+str.substring(1),
value instanceof String ? String.class : int.class);
setField.setAccessible(true);
// 调用成员方法
setField.invoke(obj, value);
}
}
}
// 调用成员变量对应set方法给对象赋值
}
/* public static void mypopulate(Object obj, Map map) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
// 获取对象的 Class 对象
Class<?> c = obj.getClass();
// 获取对象的 成员变量 和 成员set方法
Field[] fields = c.getDeclaredFields();
Method[] methods = c.getDeclaredMethods();
Set keySet = map.keySet();
for (Object key : keySet) {
Object value = map.get(key);
String filedmeth = "set" + key;
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(filedmeth)) {
method.invoke(obj, value);
}
}
}
// 调用成员变量对应set方法给对象赋值
}*/
/*public static void mypopulate(Object obj, Map map) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
// 获取对象的 Class 对象
Class<?> c = obj.getClass();
// 获取对象的 成员变量 和 成员set方法
Field[] fields = c.getDeclaredFields();
Method[] methods = c.getDeclaredMethods();
// 通过对象.成员变量 = 值
Set keySet = map.keySet();
for (Field field : fields) {
String fieldName = field.getName();
for (Object key : keySet) {
Object value = map.get(key);
if (fieldName.equals(key)) {
field.setAccessible(true);
field.set(obj, value);
}
}
}
}*/
}
package com.jxufe_ldl.homework_01.test02;
public class Person {
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}