Java反射机制

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);
        }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熠熠98

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值