反射的基本作用、关键?
- 反射是在运行时获取类的字节码文件对象,然后可以解析类中的全部成分。
- 反射的核心思想和关键就是:得到编译后的字节码(class)文件对象
反射的第一步:获取Class类对象,如此才可以解析类的全部成分
获取Class类的对象的三种方式
/**
* 目标:反射第一步:获取class对象
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 1. Class类中的一个静态方法:forName(全限定名:包名 + 类名)
Class clz = Class.forName("per.mjn.reflect.Student");
System.out.println(clz);
// 2. 类名.class
Class c1 = Student.class;
System.out.println(c1);
// 3. 对象.getClass()获取对象对应类的Class对象
Student stu = new Student();
Class c2 = stu.getClass();
System.out.println(c2);
}
}
使用反射技术获取构造器对象并使用
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
- Class类中用于获取构造器的方法
- Constructor<?>[] getConstructors() 返回所有构造器对象的数组(只能拿public的)
- Constructor<?>[] getDeclaredConstructors() 返回所有构造器对象的数组,存在就能拿到
- Constructor<?>[] getConstructor(Class<?>... parameterTypes) 返回单个构造器对象(只能拿public的)
- Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造器对象,存在就能拿到
public class TestStudent01 {
@Test
public void getConstructors() {
// a. 获取类对象
Class c = Student.class;
// b. 提取类中的全部构造器对象(只能拿public)
Constructor[] constructors = c.getConstructors();
// c. 遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
@Test
public void getDeclaredConstructors() {
// a. 获取类对象
Class c = Student.class;
// b. 提取类中的全部构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
// c. 遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
@Test
public void getConstructor() throws NoSuchMethodException {
// a. 获取类对象
Class c = Student.class;
// b. 提取类中的单个构造器对象(按照参数定位无参数构造器,只能拿public修饰的构造器)
Constructor constructor = c.getConstructor();
System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
}
@Test
public void getDeclaredConstructor() throws NoSuchMethodException {
// a. 获取类对象
Class c = Student.class;
// b. 提取类中的单个构造器对象(按照参数定位无参数构造器)
Constructor constructor = c.getDeclaredConstructor();
System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
// c. 定位某个有参构造器
Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor1.getName() + "==>" + constructor1.getParameterCount());
}
}
使用反射技术获取构造器对象并使用
Constructor类中用于创建对象的方法
- T newInstance(Object... initargs) 根据指定的构造器创建对象
- public void setAccessible(boolean flag) 设置为true,表示取消访问检查,进行暴力反射
public class TestStudentDemo2 {
@Test
public void getDeclaredConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// a. 获取类对象
Class c = Student.class;
// b. 提取类中的单个构造器对象(按照参数定位无参数构造器)
Constructor constructor = c.getDeclaredConstructor();
System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
// 如果遇到了私有的构造器,可以暴力反射
constructor.setAccessible(true); // 权限被打开
Student student = (Student) constructor.newInstance();
System.out.println(student);
// c. 定位某个有参构造器
Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor1.getName() + "==>" + constructor1.getParameterCount());
Student student1 = (Student) constructor1.newInstance("孙悟空", 1000);
System.out.println(student1);
}
}
public class FieldDemo {
/**
* 获取全部成员变量
*/
@Test
public void getDeclaredFields() {
// a. 定位Class对象
Class c = Student.class;
// b. 定位全部成员变量
Field[] fields = c.getDeclaredFields();
// c. 遍历一下
for (Field field : fields) {
System.out.println(field.getName() + "==>" + field.getType());
}
}
/**
* 获取某个成员变量
*/
@Test
public void getDeclaredField() throws NoSuchFieldException {
// a. 定位Class对象
Class c = Student.class;
// b. 根据名称定位某个成员变量
Field f = c.getDeclaredField("age");
System.out.println(f.getName() + "==>" + f.getType());
}
}
给通过反射得到的成员变量赋值
@Test
public void getDeclaredField() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// a. 定位Class对象
Class c = Student.class;
// b. 根据名称定位某个成员变量
Field agef = c.getDeclaredField("age");
agef.setAccessible(true);
Constructor constructor = c.getDeclaredConstructor();
// c. 赋值
Student s = (Student) constructor.newInstance();
agef.set(s, 18);
System.out.println(s);
// d. 取值
int age = (int) agef.get(s);
System.out.println(age);
}
总结:
1、利用反射技术获取成员变量的方式
- 获取类中成员变量对象的方法
- getDeclaredFields()
- getDeclaredField(String name)
2、反射得到成员变量可以做什么?
- 依然是在某个对象中取值和赋值。
- void set(Object obj, Object value)
- Object get(Object obj)
- 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
- setAccessible(boolean)
获取类中的全部成员方法对象
@Test
public void getDeclaredMethods() {
// a. 获取类对象
Class c = Student.class;
// b. 提取全部方法,包括私有的
Method[] methods = c.getDeclaredMethods();
// c. 遍历全部方法
for (Method method : methods) {
System.out.println(method.getName() + "返回值类型:" + method.getReturnType() + " 参数个数:" + method.getParameterCount());
}
}
通过反射调用方法
@Test
public void getDeclaredMethod() throws Exception {
// a. 获取类对象
Class c = Student.class;
// b. 提取单个方法对象
Method m = c.getDeclaredMethod("setName", String.class);
// 暴力打开权限
m.setAccessible(true);
// c. 触发方法执行
Student student = new Student();
// 注意:如果方法是没有结果回来的,那么返回的是null
Object result = m.invoke(student, "dog");
System.out.println(result);
}