今天我们来说一说反射,首先,什么是反射?
java官方对反射的解释如下
反射允许对封装类的字段,方法,和构造函数的信息进行编程访问。
这句话就是说反射允许对成员变量、成员方法和构造方法的信息进行编程访问
图中我们可以发现,代码中有很多提示语句,这些提示语句都是通过反射实现的。利用反射可以获得所有方法、方法的形参并展示出来,这个就是反射。
利用反射我们可以把成员变量获取出来,这时我们就可以获得这个成员变量的所有信息(修饰符、名字、数据类型、赋值/获取值)
利用反射我们可以把构造方法获取出来,这时我们就可以获得这个构造方法的所有信息(修饰符、名字、形参、创建对象)
利用反射我们可以把成员方法获取出来,这时我们就可以获得这个成员方法的所有信息(修饰符、名字、形参、返回值、抛出的异常、获取注解、运行方法)
利用反射我们就可以获取类里面的所有信息
综上我们可以将反射分为两类,获取和解剖
在获取时,我们并不是从java中获取的,而是从class字节码文件中获取的,也就是java编译时产生的class文件,所以我们先学习如何获取class字节码文件的对象,再学习如何从字节码文件中获取字段、构造方法以及成员方法。一旦将其获取,我们就对他们进行解剖,获取里面的所有信息。
如何获取class对象(三种方式)
1.Class.forName("全类名");
2.类名.class
3.对象.getClass();
对于java的运行过程,我们可以在源代码阶段应用第一种方式,在加载阶段应用第二种方式,在运行阶段应用第三种方式获取字节码文件。
首先,我们来演示第一种方式,建立一个student类,对其进行javabean的封装
package com.ittaotao.myreflect1;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
第一种方式Class.forName("全类名");
package com.ittaotao.myreflect1;
public class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//1.获取student类的字节码文件对象
//第一种方式
//全类名:包名+类名 找到student类,选中student,右键copy reference,就可以获取其全类名
//clazz就表示student类字节码文件的对象
Class> clazz = Class.forName("com.ittaotao.myreflect1.Student");
System.out.println(clazz);
}
}
运行结果
第二种方式 类名.class
//第二种方式
Class clazz2 = Student.class;
第三种方式 对象.getclass()
//第三种方式
Student student = new Student();
Class class3 = student.getClass();
最后我们来总结一下三种方式的使用环境,一般来说第一种是比较常用的,第二种一般更多的是作为参数进行传递,第三种是当我们已经有了这个类的对象的时候才可以使用。
综上,我们已经通过三种方式获取了字节码文件的对象,接下来我们就要通过反射来获取对应的成员变量、构造方法以及成员方法
在java中,我们有一个定义,即万物皆对象。对应上方Constructor就是构造方法的对象,Field就是成员变量的对象,第三个Method就是成员方法的对象。
首先,我们要来学习通过反射获取构造方法
这些方法全部存在于class类当中
接下来进行代码实现
首先,依旧是封装一个student的javabean类
package com.ittaotao.myreflect2;
public class 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 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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
接下来,利用反射获取构造方法(公共的和连同私有一起获取的)
package com.ittaotao.myreflect2;
import java.lang.reflect.Constructor;
public class MyReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException {
//1.构造方法是在字节码文件中,所以需要获取class字节码文件
Class> clazz = Class.forName("com.ittaotao.myreflect2.Student");
//2.获取构造方法
//该方法只能获得公共的构造方法(public)
Constructor>[] cons = clazz.getConstructors();
//3.遍历数组
for (Constructor> con :cons){
System.out.println(con);
}
System.out.println("-------------------------");
//连同私有方法一起获取
Constructor>[] cons2 = clazz.getDeclaredConstructors();
for (Constructor> con1 : cons2) {
System.out.println(con1);
}
}
}
运行结果如下
获取单个方法
//获取单个方法,不加s即可
Constructor> cons3 = clazz.getConstructor();
System.out.println(cons3);
System.out.println("----------------------------");
//获取name的构造方法
Constructor> cons4 = clazz.getDeclaredConstructor(String.class);
System.out.println(cons4);
System.out.println("-----------------------------");
//获取protected声明的构造方法
Constructor> cons5 = clazz.getDeclaredConstructor(int.class);
System.out.println(cons5);
System.out.println("-----------------------------");
//获取两个参数的构造方法
Constructor> cons6 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(cons6);
运行结果
接下来我们简单的介绍一下创建对象
//getDeclaredConstructor只能获取私有声明的构造方法,但不能创建对象,因此使用下面这句代码表示临时取消权限校验
cons6.setAccessible(true);
Student student = (Student) cons6.newInstance("张三", 23);
System.out.println(student);
以上就是获取class对象,以及利用反射获取构造方法的说明了,构造方法我并没有罗列全,有的方法,各位小伙伴们也可以自己根据图片中的方法试一下!
如有问题还请各位评论区多多提出!