[Java基础] 框架设计的灵魂---反射

本文介绍了Java的反射机制,解释了如何将类的组成部分封装为对象,并探讨了反射在程序运行时操纵对象和解耦代码的重要性。详细讲解了Class对象的获取方式,包括class.forName()、类名.class和对象.class。此外,还讨论了Field、Constructor和Method对象的操作,以及如何进行暴力反射。最后,通过一个案例展示了如何利用反射在不修改原有代码的情况下创建对象并执行任意方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射机制
  • 将类的各个组成部分封装为其他对象,这就是反射机制
  • Java代码在计算机里会经历三个阶段:
    • 源代码阶段(Source源代码):.java文件通过编译形成.class文件,字节码文件加载进内存中
    • class类对象阶段:通过类加载器(ClassLoader)加载形成类对象(包括有成员变量 Field[] fields构造方法Constructor[] cons成员方法Method[] methods
    • Runtime运行时阶段:通过类对象创建对象
  • 反射机制的体现就是将class文件里的成员变量封装为类对象里的Field对象,构造方法封装为Constructor对象,将成员方法封装为Method对象
  • 反射的好处:
    • 1、可以在程序的运行过程中,操纵对象
    • 2、可以解耦,提高代码的可扩展性
Class对象
  • 获取class对象的三种形式:

    • 1、class.forName(“全类名”):将字节码文件加载进内存,返回class对象(多用以配置文件,将类定义在配置文件中,读取文件,加载类)
    • 2、类名.class:通过类名的属性class获取(多用于参数的传递)
    • 3、对象.class(多用于对象获取字节码的方式)

    同一个字节码文件(*.class)在一次程序运行中,只会被加载一次,无论通过哪一种方式加载获取的Class对象都是同一个

1、获取成员变量
	* Field[] getFields();//获取所有public修饰的成员变量,包括父类
	* Field getField(String name);//也只能获取所有public修饰的成员变量

	* Field[] getDeclaredFields();//获取所有的成员变量,不考虑访问权限修饰符,不包括父类
	* Field getDeclaredField(String name);
2、获取构造方法
	* Constructor<?>[] getConstructors();//获取所有的public修饰的构造器
	* Constructor<T> getConstructor(<?>...parameterTypes);

	* Constructor<?>[] getDeclaredConstructors();
	* Constructor<T> getDeclaredConstructor(<?>...parameterTypes);
3、获取成员方法
	* Method[] getMethods();//获取所有的方法,包括Object类的方法
	* Method getMethod(String name,<?>... parameterTypes);
	
	* Method[] getDeclaredMethods();
	* Method getDeclaredMethod(String name,<?>... parameterTypes);
4、获取类名
	* String getName();
  • Field成员变量的操作

    • 1、设置值:void set(Object obj, Object value)

    • 2、获取值:Object get(Object obj)

    • 3、忽略访问修饰权限符的安全检查:setAccessible(true)

    • Field getDeclaredField(String name):获取之后,对于private修饰符的成员变量,进行set,get操作时,将会报错:

      Exception in thread "main" java.lang.IllegalAccessException: Class Reflect.ReflectDemo can not access a member of class Reflect.Person with modifiers "private"
      	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
      	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
      	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
      	at java.lang.reflect.Field.get(Field.java:390)
      
    • 因此,要想在类外操作private修饰的变量,将要忽略访问修饰权限符的安全检查,也就是暴力反射setAccessible(true)

  • Contructor构造方法的操作

    • 构造器的作用就是用来创建对象的。
    • 创建对象:T newInstance(Object... initargs)
      • 如果是用空参的构造方法来创建一个对象,可以直接使用Class类的T newInstance()来创建
    • 要获取私有的构造器的情况,也是用setAccessible(true)来暴力反射
  • Method构造方法的操作

    • 获取所有的方法,会获取除自定义的方法外,还会获取Object类的所有方法
    • 执行方法:Object invoke(Object obj, Object... args)
    • 获取方法名称:String getName()
案例
  • 需求:写一个“框架”,在不改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
  • 实现:
    • 1、配置文件
    • 2、反射
  • 步骤:
    • 1、将需要创建的对象的全类名和需要执行的方法定义到配置文件中
    • 2、在程序中加载读取配置文件
    • 3、使用反射技术来加载类文件进内存
    • 4、创建对象
    • 5、执行方法
//pro.properties
className=domain.Person
methodName=eat
public class ReflectTest {

    public static void main(String[] args) throws Exception {
        //可以创建任意类的对象,可以执行任意方法
        //1  创建Properties对象
        Properties pro = new Properties();
        //2  加载配置文件,转换成一个集合
        //获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream("pro.properties");
        pro.load(stream);
        //3  获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //4  加载该类进内存
        Class cls = Class.forName(className);
        //5  创建对象
        Object o = cls.newInstance();
        //6  获取方法对象
        Method method = cls.getMethod(methodName);
        //7  执行方法
        method.invoke(o);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值