Java反射的概念:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性(构造方法,成员变量,成员方法);这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想理解好Java的反射机制,我们需要有一个概念:就是把java中所有的东西都用对象来理解,
一个方法也可以是一个对象,一个字节码文件也可以是一个对象。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象
获取class对象的方式:
1:1:Class.forName("全类名“) 最为常用:
2:类名.class 更多的是当作参数进行传递
3:对象.class 当我们已经有了这个类的对象,才可以使用
/*
获取class对象的三种方式:
1:Class.forName("全类名“) 最为常用
2:类名.class 更多的是当作参数进行传递
3:对象.class 当我们已经有了这个类的对象,才可以使用
*/
Class<?> clazz1 = Class.forName("Student");
System.out.println(clazz1);
Class<Student> clazz2 = Student.class;
System.out.println(clazz2);
Student st = new Student();
Class<? extends Student> clazz3 = st.getClass();
System.out.println(clazz3);
获取构造方法:
首先在Student对象中创建四个不同的类型的构造方法做为演示:
private String name;
private int age;
public Student() {
}
public Student(String name){
this.name = name;
}
protected Student(int age) {
this.age = age;
}
private Student(String name,int age){
this.name = name;
this.age = age;
}
获取所有公共构造方法对象数组(public):clazz.getConstructors()
获取所有构造方法对象的数组:clazz.getDeclaredConstructors()
获取单个公共构造方法对象数组(public):clazz.getConstructors()
获取单个构造方法对象的数组:clazz.getDeclaredConstructors(),用这个方法的时候需要注意传参。
// 2:获取构造方法
// 获取所有公共构造方法对象数组(public)
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con:cons1){
System.out.println(con);
}
// 获取所有构造方法对象的数组
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con:cons2){
System.out.println(con);
}
//返回单个公共构造方法对象 需要注意传参
Constructor con1 = clazz.getConstructor();
System.out.println(con1);
Constructor con2 = clazz.getConstructor(String.class);
System.out.println(con2);
//返回单个构造方法对象
Constructor con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);
Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con4);
获取构造方法的权限修饰符
int modifiers = con4.getModifiers();
System.out.println(modifiers);
这里需要说一下:这个权限修饰符对我们没有什么用,因为这个modifiers是一个int型的数,他代表了public protected和private各种修饰符。
不过这个参数能传给idea,看下面的图,这个提示中只有三个选项,无参,name,age,并没有(name,age)这个选择,因为这个(name,age)是一个private的方法,所以没有提示,idea就是根据这个modifiers来判断的。
获取构造方法的参数
看下面这张图,idea通过反射这个机制将所获得的参数做成了一个可视化的效果展示出来。
这两个方法也充分展示了,反射机制是框架的核心。
//获得构造方法的参数
Parameter[] parameters = con4.getParameters();
for (Parameter par:parameters){
System.out.println(par);
}
用构造方法来创建对象(包括private对象也可以)
因为这个con4是用private(name,age)方法创建的对象,所以,我们传参数的时候,也需要将对应的参数传进去。
con4.setAccessible(true)可以临时取消权限验证,如果这一行代码,程序就会报错。
//暴力反射:表示临时取消权限校验
con4.setAccessible(true);
Student stu = (Student) con4.newInstance("李四",18);
System.out.println(stu);
获取成员变量:
public String name;
private int age;
protected String gender;
获取所有公共成员变量:
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
获取全部成员变量:
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field:declaredFields){
System.out.println(field);
}
获取单个公共成员变量:
Field field = clazz.getField("name");
System.out.println(field);
获取私有成员变量:
Field age = clazz.getDeclaredField("age");
System.out.println(age);
//获取权限修饰符
int modifiers = age.getModifiers();
System.out.println(modifiers);
//获取成员变量的名字
String name = age.getName();
System.out.println(name);
//获取成员变量的数据类型
Class<?> type = age.getType();
System.out.println(type);
获取私有变量的值:
获取变量中的值之前,我们得先创建一个对象,并给这个对象赋值。
Field age = clazz.getDeclaredField("age");
Student st = new Student("张三",18,"男");
age.setAccessible(true);
int value = (int) age.get(st);
System.out.println(value);
这里有一个注意点:你创建的这个成员变量的对象的类型,
这里的Field age对应的是Studengt类中的private int age这个成员变量,所以对应的返回值是(int)(就类似于这个private int age反射出了一个对象,你想获得这个对象的值,返回的值需要和这个类型一样)。
更改成员变量的值:
//修改成员变量的值
age.set(st,28);
System.out.println(st);
获取成员方法:
先贴一段Student类的代码:
public void sleep(){
System.out.println("睡觉");
}
private void eat(String something) throws ArithmeticException,IllegalAccessException,NullPointerException{
System.out.println("在吃:"+something);
}
返回所有公共成员方法对象的数组(包括父类):
Method[] methods = clazz.getMethods();
for (Method method:methods){
System.out.println(method);
}
返回所有成员方法对象的数组(不包括父类)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method method:declaredMethods){
System.out.println(method);
}
返回指定单一成员方法 参数:方法名 + 参数的类型
Method method = clazz.getDeclaredMethod("eat",String.class);
System.out.println(method);
获取方法的修饰符:
int modifiers = clazz.getModifiers();
System.out.println(modifiers);
获取方法的形参
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
获取方法的返回值
Class<?> returnType = method.getReturnType();
System.out.println(returnType);
获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
/**
* 用方法对象(method)去调用这个方法
* invoke(Object obj, Object... args)运行方法
* 参数一:用obj这个对象调用这个方法
* 参数二:调用方法的传递的参数(没有就不用写)
* 返回值:该方法的返回值(没有就不写)
*/
这个方法蛮重要
Student st = new Student();
method.setAccessible(true);
method.invoke(st, "汉堡");