反射
反射的原理
Java 中的所有类都是一个模板
整个类对于Java而言都是一个类的类型Class类型
class 类名 {
成员变量; // Field
成员方法; // Method
构造方法; // Constructor
}
构造方法类【Constructor】
修饰符 类型 (形参列表);
对于一个构造方法而言,在调用过程中唯一的区别是形式参数列表,同时需要关注,当前构造方法所在哪一个类
成员方法类【Method】
修饰符 返回值类型 方法名 (形参列表);
对一个成员方法而言,在调用方法的过程中,我们所关注的是方法名和形式参数列表数据类型,同时需要关注,当前成员方法所在哪一个类
成员变量类【Field 】
修饰符 数据类型 成员变量名;
对于一个成员变量而言,变量名是唯一的,同时需要关注,当前成员变量所在哪一个类
获取Class对象
Class 类型是 Java 中对于所有类(类和接口)一种整体的模版描述。代码中使用使用 Class 类型对象。Class 类型对象是对应 Java 类型在内存方法区空间内容。
获取class对象的三种方式 1.Class.forName("全类名") 2.类名.class 3.对象.getClass();
public class MyReflectDemo1 {
/*
获取class对象的三种方式
1.Class.forName("全类名")
2.类名.class
3.对象.getClass();
*/
public static void main(String[] args) throws ClassNotFoundException {
//1.第一种方式
//全类名 : 包名 + 类名
//最为常用
Class clazz1 = Class.forName("com.xxx.mfeflect.Student");
//2第二种方式
//一般更多的是当作参数进行传递
Class<Student> clazz2 = Student.class;
//第三种方式
//当我们已经有了这个类的对象时,才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz2 == clazz1);
System.out.println(clazz2 == clazz3);
}
}
无论通过哪一种形式获Class 对象,只要是同一个类型, 得到的都是同一个 Class 对象, 对应的是内存【方法区】的同一个数据空间。
获取构造方法
Class类中用于获取构造方法的方法:
获取当前类的全部公开构造方法,返回一个数组
Constructor<?>[] getConstructors()
【暴力反射】获取当前类的全部构造方法(包括私有构造方法),返回一个数组
Constructor<?>[] getDeclaredConstructors()
根据指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,【非私有化】构造方法
Constructor<T> getConstructors(Class<?>...parameterTypes)
【暴力反射】根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象 ,可以获取私有化构造方法
Constructor<T> getDeclaredConstructors(Class<?>...parameterTypes)
代码演示
public class MyReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取class字节码文件对象
Class clazz = Class.forName("com.xxx.mreflectmethod.Student");
//获取构造方法
Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
//暴力反射,获取所有构造方法
Constructor[] con2 = clazz.getDeclaredConstructors();
for (Constructor con : con2) {
System.out.println(con);
}
//创建构造方法对象
//无参构造
Constructor con1 = clazz.getConstructor();
System.out.println(con1);
//有参构造
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);
Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);
//表示临时取消权限校验
con4.setAccessible(true);
Student stu = (Student)con4.newInstance("张三",23);
System.out.println(stu);
}
}
Object newInstance(Object... parameterValues); // 重点方法 ★
通过 Constructor 构造方法对象调用 newInstance 进行实例化对象操作,当前 newInstance 方法所需参数是构造方法参数列表对应的实际参数,采用的参数形式为 Object… 支持任意类型的不定长参数。可以支持没有参数,一个参数或者多个参数,在方法内部是一个 Object 类型的数组
new 构造方法形式局限性很大,通过反射方式操作,可以满足多种多样的类型需求。反射操作完成整体数据解析和赋值操作,并且
代码可以复用,相较于原本的 new + 构造方法形式,适配性更好!!!
反射获取成员方法【重点】
可以获取 Class 对象对应类型的所有非私有化成员方法对象数组,包括父类继承给子类可以供子类使用的成员方法
Method[] getMethods();
【暴力反射】可以获取 Class 对象对应类型的所有成员方法对象数组,包括私有化成员方法,但是不包括继承方法父类的成员方法。有且只有子类自身方法
Method[] getDeclaredMethods();
根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,只能是非私有化成员方法和父类继承给子类使用的方法。
Method getMethod(String methodName, Class... parameterTypes);
【暴力反射】根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,包括私有化成员方法,不包括父类继承到子类的方法。仅获取子类自有方法
Method getDeclaredMethod(String methodName, Class... parameterTypes);
代码演示
//1.获取class字节码文件对象
Class clazz = Class.forName("com.xxx.mreflectmethod.Student");
//获取里面的所有的方法的对象(包含父类中所有的公共方法)
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取里面的所有的方法的对象(不能是父类的,但是可以是本类中私有的)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取指定的单一方法
Method m = clazz.getDeclaredMethod("eat", String.class);
System.out.println(m);
成员方法对象执行对应方法操作
//方法运行
Method类中用于创建对象的方法
object invoke(Object obj,Object...args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写);
invoke 方法返回值类型为 Object 类型,支持当前目标方法的返回值
返回值:方法的返回值(没有就不写)
Student s = new Student();
m.setAccessible(true);
//参数一s:表示方法的调用者
//参数二“汉堡包”:表示在调用方法的时候传递的实际参数
/* Object result = m.invoke(s, "汉堡包");
System.out.println(result);*/
String result = (String) m.invoke(s, "汉堡包");
System.out.println(result);
反射获取成员变量
Class类中用于获取成员变量的方法
Field[] getFields(): 返回所有公共成员变量对象的数组
Field[] getDeclaredFields(): 返回所有成员变量对象的数组
Field getField(String name): 返回单个公共成员便变量对象
Field getDeclaredField(String name): 返回单个成员便变量对象
Field类中用于创建对象的方法
void set(object obj,object value): 赋值
object get(object obj) 获取值
暴力解决权限问题
对应方法
void setAccessible(boolean flag); // 重点方法 ★ 反射操作中 Constructor, Method ,Field 对象都可以调用该方法 解决 私有化反射对象权限操作问题 public static void setAccessible(AccessibleObject[] array, boolean flag) AccessibleObject 类工具方法,所需参数是 AccessibleObject 数组和对应的权限标记,flag 通常为 true。 Field Method Constructor 都是 AccessibleObject 子类
参数提供为 true 当前私有化构造方法对象有对应的操作权限。
反射的其他常用方法
获取方法的修饰符
获取方法的名字
获取方法的形参
获取方法的返回值
获取方法的抛出的异常
//获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);
//获取方法的名字
String name = m.getName();
System.out.println(name);
//获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
// 获取方法的抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
反射就总结到这,算是反射的初级使用吧