Java中的反射

一、反射的概述

反射的引入

问题:IDEA中的对象是怎么知道类有哪些属性,哪些方法的呢?

  • 通过反射技术对象类进行了解剖得到了类的所有成员。

反射的概念

  • 反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量,成员方法,构造方法)

使用反射操作类成员的前提

  • 要获得该类字节码文件对象,就是Class对象

反射机制的功能:

  • 在运行时获取【任意】一个对象所属的类型

  • 在运行时获取【任意】一个类的构造

  • 在运行时构造【任意】一个类的对象

  • 在运行时获取【任意】一个类所具有的成员变量

  • 在运行时设置或者获取【任意】一个属性的值

  • 在运行时获取【任意】一个类所具有的成员方法

  • 在运行时调用【任意】一个对象的方法

反射在实际开发中的应用

  • 开发IDE(集成开发环境),比如IDEA,Eclipse
  • 各种框架的设计和学习 比如Spring,Hibernate,Struct,Mybaits…

提示!

在所有的具备的功能中,都是针对任意的对象进行操作,说明反射机制具备很强的灵活性和通用性。

总体而言:

Java的反射机制可以动态性的操作类、属性、方法,为此都推出了相应的类来进行描述:

Class类:描述所有的类的类型;

Constructor类:描述所有的构造的类型;

Field类:描述所有的属性的类型;

Method类:描述所有的方法的类型;

以上所有的这些类,其实就是将一个class类进行了分解。

二、Class类对象获取的三种方式

2.1、三种获取方式

  • 方式1: 通过类名.class获得
  • 方式2:通过对象名.getClass()方法获得
  • 方式3:通过Class类的静态方法获得: static Class forName(“类全名”)
    • 每一个类的Class对象都只有一个。
package com.reflection;


public class Student {
    //成员变量:一个私有,一个默认,一个公共
    private String name;
    int age;
    public String address;

    //构造方法:一个私有,一个默认,两个公共
    public Student() {
    }

    private Student(String name) {
        this.name = name;
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    //成员方法:一个私有,四个公共
    private void function() {
        System.out.println("function");
    }

    public void method1() {
        System.out.println("method");
    }

    public void method2(String s) {
        System.out.println("method:" + s);
    }

    public String method3(String s, int i) {
        return s + "," + i;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.reflection;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 上午9:32
 * @Description: 反射的简单使用
 */

public class ReflectDemo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1. 获取Class对象
        Class<Student> c1 = Student.class;
        // 2. 创建对象
        Student student = new Student();
        // 3. 通过对象名.getclass方法获
        Class c2 = student.getClass();
        // 判断两者是不是同一个对象
        System.out.println(c1 == c2);

        // 通过class类静态方法获得:
        Class<?> c3 = Class.forName("com.reflection.Student");
        System.out.println(c1 == c3);
        System.out.println(c2 == c3);
    }
}

image-20240810095216760

2.2、Class类的常用方法

  • String getSimpleName(); 获得类名字符串:类名
  • String getName(); 获得类全名:包名+类名
  • T newInstance() ; 创建Class对象关联类的对象
package com.reflection;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 上午9:51
 * @Description: Class类常用方法
 */

public class ReflectDemo02 {
    public static void main(String[] args) throws Exception {
        // 获得Class对象
        Class c = Student.class;
        // 获得类名字符串:类名
        System.out.println(c.getSimpleName());
        // 获得类全名:包名+类名
        System.out.println(c.getName());
        // 创建对象
        Student stu = (Student) c.newInstance();
        System.out.println(stu);
    }
}

image-20240810095356606

三、反射之操作构造方法

反射之操作构造方法的目的:获得Constructor对象来创建类的对象。

Constructor类概述:类中的每一个构造方法都是一个Constructor类的对象

方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 上午10:13
 * @Description: Constructor类的概述
 */

public class ReflectDemo03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取class对象
        Class<?> aClass = Class.forName("com.reflection.Student");
        // Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数
        // Constructor<?>[] cons = c.getConstructors();
        // Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组
        Constructor<?>[] cons = aClass.getDeclaredConstructors();
        for (Constructor<?> con : cons) {
            System.out.println(con);
        }
        System.out.println("--------");
        // Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数
        // Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数
        // 参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
        Constructor<?> con = aClass.getConstructor();
        // Constructor提供了一个类的单个构造函数的信息和访问权限
        // T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
        Object obj = con.newInstance();
        System.out.println(obj);
        System.out.println("--------");
        Student s = new Student();
        System.out.println(s);
    }
}

image-20240810103831913

3.1、反射获取构造方法并使用练习1

案例需求

  • 通过反射获取公共的构造方法并创建对象
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:13
 * @Description:
 */

public class ReflectDemo04 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取class类对象
        Class<?> aClass = Class.forName("com.reflection.Student");
        // public Student(String name, int age, String address)
        // Constructor<T> getConstructor(Class<?>... parameterTypes)

        Constructor<?> con = aClass.getConstructor(String.class, int.class, String.class);
        // 基本数据类型也可以通过.class得到对应的Class类型
        // T newInstance(Object... initargs)
        Object obj = con.newInstance("林青霞", 30, "西安");
        System.out.println(obj);
    }

}

image-20240810121914386

3.2、反射获取构造方法并使用练习2

案例需求

  • 通过反射获取私有构造方法并创建对象
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:18
 * @Description:
 */

public class ReflectDemo05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取class类对象
        Class<?> aClass = Class.forName("com.reflection.Student");
        //private Student(String name)
        //Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        Constructor<?> con = aClass.getDeclaredConstructor(String.class);

        //暴力反射
        //public void setAccessible(boolean flag):值为true,取消访问检查
        con.setAccessible(true);
        
        Object obj = con.newInstance("林青霞");
        System.out.println(obj);
    }
}

image-20240810122225092

四、反射之操作成员方法

反射之操作成员方法的目的:操作Method对象来调用成员方法
Method类概述:每一个成员方法都是一个Method类的对象。

方法名说明
Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>… parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象

Method类用于执行方法的方法

方法名说明
Objectinvoke(Object obj,Object… args)调用obj对象的成员方法,参数是args,返回值是Object类型
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:24
 * @Description:
 */

public class ReflectDemo06 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取class类对象
        Class<?> aClass = Class.forName("com.reflection.Student");

        // Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类
        // Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
        // Method[] methods = c.getMethods();
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("--------");
        // Method getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法
        // Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象
        // public void method1()
        Method m = aClass.getMethod("method1");

        Constructor<?> con = aClass.getConstructor();
        Object o = con.newInstance();
        // 注意这种方法是错误的
        // o.m();

        // 在类或接口上提供有关单一方法的信息和访问权限
        // Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法
        // Object:返回值类型
        // obj:调用方法的对象
        // args:方法需要的参数
        m.invoke(o);


    }
}

image-20240810123719051

反射获取成员方法并使用练习:通过反射获取成员方法并调用

package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:39
 * @Description:
 */

public class ReflectDemo07 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        // 获取class类对象
        Class<?> c = Class.forName("com.reflection.Student");
        // Student s = new Student();
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        // s.method1();
        Method m1 = c.getMethod("method1");
        m1.invoke(obj);
        System.out.println("--------");
        // s.method2("林青霞");
        Method m2 = c.getMethod("method2", String.class);
        m2.invoke(obj, "林青霞");
        System.out.println("--------");
//        String ss = s.method3("林青霞",30);
//        System.out.println(ss);
        Method m3 = c.getMethod("method3", String.class, int.class);
        Object o = m3.invoke(obj, "林青霞", 30);
        System.out.println(o);
        System.out.println("--------");
        // s.function();
        Method m4 = c.getDeclaredMethod("function");
        m4.setAccessible(true);
        m4.invoke(obj);


    }
}

image-20240810124353337

五、反射之操作成员变量

反射之操作成员变量的目的:通过Field对象给对应的成员变量赋值和取值

Field类概述:每一个成员变量都是一个Field类的对象。

方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象

Field类用于给成员变量赋值的方法

方法名说明
voidset(Object obj,Object value)给obj对象的成员变量赋值为value
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:46
 * @Description:
 */

public class ReflectDemo08 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
        // 获取class类对象
        Class<?> c = Class.forName("com.reflection.Student");

        // Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段
        // Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段
//        Field[] fields = c.getFields();
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("--------");
        // Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段
        // Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段
        Field address = c.getField("address");
        // 获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

//        obj.addressField = "西安";

        // Field提供有关类或接口的单个字段的信息和动态访问
        // void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值
        address.set(obj, "西安");
        System.out.println(obj);
        System.out.println("--------");
        Student s = new Student();
        s.address = "西安";
        System.out.println(s);

    }
}

image-20240810125301273

反射获取成员变量并使用练习:

案例需求

  • 通过反射获取成员变量并赋值
package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:53
 * @Description:
 */

public class ReflectDemo09 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
        // 获取class类对象
        Class<?> c = Class.forName("com.reflection.Student");
        // Student s = new Student();
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();
        System.out.println(obj);

        // s.name = "林青霞";
//        Field nameField = c.getField("name"); //NoSuchFieldException: name
        Field nameField = c.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(obj, "林青霞");
        System.out.println(obj);

        // s.age = 30;
        Field ageField = c.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(obj, 30);
        System.out.println(obj);

        // s.address = "西安";
        Field addressField = c.getDeclaredField("address");
        addressField.setAccessible(true);
        addressField.set(obj, "西安");
        System.out.println(obj);
    }
}

image-20240810125516734

六、综合案例

6.1、越过泛型检查

通过反射技术,向一个泛型为Integer的集合中添加一些字符串数据

package com.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午12:57
 * @Description: 通过反射技术,向一个泛型为Integer的集合中添加一些字符串数据
 */

public class ReflectDemo10 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> array = new ArrayList<>();

        // array.add(10);
        // array.add(20);
        // array.add("hello");

        Class<? extends ArrayList> c = array.getClass();
        Method m = c.getMethod("add", Object.class);
        m.invoke(array, "hello");
        m.invoke(array, "world");
        m.invoke(array, "java");

        System.out.println(array);
    }
}

image-20240810125954364

6.2、运行配置文件中指定类的指定方法

通过反射运行配置文件中指定类的指定方法

package com.reflection;

public class Teacher {
    public void teach() {
        System.out.println("用爱成就学员");
    }
}

class.txt文件:

className=com.reflection.Teacher
methodName=teach
package com.reflection;

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @Author: 史小创
 * @Time: 2024/8/10 下午1:05
 * @Description:
 */

public class ReflectDemo11 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException, InstantiationException {
        // 加载数据
        Properties prop = new Properties();
        FileReader fr = new FileReader("class.txt");
        prop.load(fr);
        fr.close();

        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");

        // 通过反射来使用
        Class<?> c = Class.forName(className);

        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        Method m = c.getMethod(methodName);// study
        m.invoke(obj);
    }
}

image-20240810130850656

环境说明:

image-20240810124904516

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值