文章目录
1. 反射机制简介
在介绍反射机制之前我们要先明确两个概念:
1.类加载器(ClassLoader)
- 类加载器负责将类的字节码文件(.class文件)加载到内存中,并生成对应的Class对象。
2.Class对象
- java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件。
在了解上面的两个概念后,我们先来看一下普通程序的运行过程是先将后缀名为 .java 的源文件编译成后缀名为 .class 的字节码文件,然后通过 obj.method() 的形式调用具体的方法。
而Java的反射机制其实就上面的过程反转过来,即我们想调用某一个对象的某一个方法,那么我们就先获取后缀名为 .class 的字节码文件,然后通过这个字节码文件我们就可以访问这个类中的构造方法、成员方法以及成员属性。
经过了上面了介绍,我们进一步来描述一下Java反射机制的定义:
- Java反射(Reflection)允许应用程序在运行时借助于反射API,来获取所有类或接口的内部信息,并且能直接操作任意对象的内部属性及方法。反射机制的核心类为java.lang.Class。简单来说,它是在程序运行过程中分析类的一种能力。
- 反射能做什么?
- 分析类
- 加载并初始化一个类
- 查看类的所有属性和方法
- 查看并使用对象
- 查看一个对象的所有属性和方法
- 使用对象的任意属性和方法
- 反射的应用场景
- 构建通用的工具
- 搭建具有高度灵活性和扩展性的系统框架
2. 通过反射创建对象
为了方便测试,我们首先创建一个Student类,代码如下:
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//无参构造方法
public Student(){}
//公共带参构造方法
public Student(String name){
System.out.println("名字是:"+name);
}
//私有带参构造方法
private Student(int age){
System.out.println("年龄是:"+age);
}
public void test1(){
System.out.println("公共的空参方法");
}
public void test2(int a){
System.out.println("公共传参方法,传参为:"+a);
}
private int test3(int a,int b){
System.out.println("私有传参方法");
return a+b;
}
}
2.1反射获取Class对象
通过反射获取Class对象主要有三种方式:
//方式一:通过类实例获取
Class clazz1 = stu.getClass();
//方式二:直接调用class获取
Class clazz2 = Student.class;
//方式三:通过Class.forName获取,传入类的路径名
Class clazz3 = Class.forName("reflection.Student");
2.2通过反射获取构造方法
我们通过方法获取Constructor对象,即构造器对象,而通过构造器对象能创建一个对象。
//1.获取Class(字节码文件)对象
Class clazz = Class.forName("reflection.Student");
//2.获取构造器对象
//获取公共无参构造
Constructor c1 = clazz.getConstructor();
//获取公共的有参构造,传入对应字节码文件对象
Constructor c2 = clazz.getConstructor(String.class);
//获取私有有参构造
Constructor c3 = clazz.getDeclaredConstructor(int.class);
//获取Student类的所有公共构造方法
Constructor[] cons = clazz.getConstructors();
//获取构造器的名字,看是哪个类的构造方法
String name = c2.getName();
System.out.println(name);
2.3反射创建对象的常用方法
我们一般通过两种方法创建对象:
- 通过Class类的newInstance创建一个实例,该方法调用无参构造器。
- 通过构造函数Constructor类创建一个实例。
//获取Class(字节码文件)对象
Class clazz = Class.forName("reflection.Student");
//获取构造方法
Constructor c2 = clazz.getConstructor(String.class);
//创建对象
//方式一:通过Class类的newInstance创建实例,返回的是Object类型的对象
Object obj1 = clazz.newInstance();
System.out.println(obj1 .getClass());
//方式二:通过构造函数Constructor类创建一个实例
Object obj2 = c2.newInstance("李四");
System.out.println(obj2 .getClass());
//也可以进行以下强制转化
Student stu = (Student) obj2;
System.out.println(stu);
3. 反射获取成员方法
我们可以通过反射获取 Method 对象,也就是方法对象,它属于java.base模块,java.lang.reflect包。
3.1通过Class对象获取方法
//1.返回一个Method对象,仅限公共成员方法,需要传入方法名和方法参数列表
getMethod(String name, Class<?>… parameterTypes)
//2.返回一个Method对象,可获取私有成员方法,需要传入方法名和方法参数列表
getDeclaredMethod(String name, Class<?>... parameterTypes)
//3. 返回此类所有(不含私有)方法的数组
getMethods()
3.2Method的常用方法
// 返回方法名
String getName()
// 在指定对象上调用此方法,参数为args
Object invoke(Object obj, Object… args)
3.3示例
public static void main(String[] args) throws Exception {
//通过反射获取Class对象
Class clazz = Class.forName("reflection.Student");
//通过反射获取公共无参构造方法
Constructor con = clazz.getConstructor();
//通过反射创建 Student 对象实例
Student stu = (Student)con.newInstance();
//反射获取成员方法
//1.反射获取公共空参方法
Method method1 = clazz.getMethod("show1");
System.out.println(method1);
//打印方法名
System.out.println(method1.getName());
//调用该方法
method1.invoke(stu);
//2.反射获取公共带参方法
Method method2 = clazz.getMethod("show2", int.class);
//调用该方法
method2.invoke(stu,100);
//3.反射获取私有带参方法
Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
//私有方法需要开启暴力反射才能调用
method3.setAccessible(true);
int sum = (int)method3.invoke(stu, 1, 3);
System.out.println(sum);
//4.反射获取所有成员方法,不包括私有成员方法
Method[] methods = clazz.getMethods();
for(Method method:methods){
System.out.println(method);
}
}
4. 反射获取类的属性
Field对象,域(属性、成员变量)对象,属于java.base模块,java.lang.reflect包。
4.1通过Class对象获取属性
//1.返回一个Field对象,仅公共属性,需要传入属性名
getField(String name)
//2. 返回一个Field对象,可获取私有属性,需要传入属性名
getDeclaredField(String name)
//3.返回此类所有(不包含私有)属性的数组
getDeclaredField()
//4.返回此类所有(含私有)属性的数组
getDeclaredFields()
4.2Field的常用方法
// 返回方法名
String getName()
// 将此属性的可访问性设置为指定布尔值
boolean setAccessible(boolean flag)
//给指定对象设定传入的指定值
set(Object obj, Object value)
4.3示例
public static void main(String[] args) throws Exception {
//通过反射获取Class对象
Class clazz = Class.forName("reflection.Student");
//通过反射获取公共无参构造方法
Constructor con = clazz.getConstructor();
//通过反射创建 Student 对象实例
Student stu = (Student)con.newInstance();
//反射获取成员属性
//1.反射获取共有属性
Field field1 = clazz.getField("id");
//给stu对象的该属性赋值
field1.set(stu,1);
System.out.println(field1);
//2.反射获取私有属性
Field field2 = clazz.getDeclaredField("name");
// 将此属性的可访问性设置为true
field2.setAccessible(true);
//给stu对象的该属性赋值
field2.set(stu,"李生辉");
System.out.println(stu);
}
//3.反射获取此类所有(含私有)属性的数组
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields){
System.out.println(field);
}