java 反射机制,为什么要用反射?

  • 反射:是框架的设计灵魂。那框架又是什么呢? 框架:是一个半成品软件。可以在框架的基础上进行软件开发,这样可以简化代码。
  • 回到反射上面,反射:将类的各个组成部分封装成其他对象,这就是反射机制。这么说还是不懂反射是什么,别急,耐心看下去。

1.先了解下java代码在计算机中需要经历三个阶段:

第一个阶段:Source源代码阶段。通俗点来说这个阶段就是平时我们写的java代码 Demo1.java,经过javac编译后生成一个字节码文件 Demo1.class。字节码文件里面包含成员变量,成员方法,构造函数。这两个文件都只是存放在硬盘上,还没有进内存。
在这里插入图片描述

第三个阶段:Runtime运行时阶段。第一个阶段写的文件怎么去使用呢,这就需要在第三阶段new Demo1() 生成一个对象。但对象是在内存中的,第一个阶段生成的文件都没进内存,那第三个阶段怎么去使用呢。这里就需要第二个阶段,把字节码文件加载进内存。

第二个阶段:Class类对象阶段。通过类加载器(ClassLoader)把字节码文件Demo1.class加载进内存。那在内存中怎么去描述这个字节码文件呢?其实,在java中万物皆对象;在第二个阶段中就是通过Class这个类对象去描述字节码文件的。Class类对象里面有三个比较重要的东西,成员变量,成员方法和构造方法;把这三部分都封装为对象,成员变量封装为Field对象,构造方法封装为Constructor对象,成员方法封装为Method对象。因为成员变量可能不止一个,所以一般都用数组Field[ ] fields来描述成员变量,其他两部分也是用数组的形式。后面就是通过这个Class类对象来创建真正的对象(比如new Demo1()),这就是从第二阶段到第三阶段。

再看下图,对这三个阶段的理解就清晰多了。
在这里插入图片描述

2.获取Class对象:

  • 我们平时写的代码,也就是第一阶段,没有加载进内存,只是存储在硬盘上。那么这个时候怎么获取Class对象呢?可以使用 Class.forName(“全类名”);在第二阶段时,已经加载到内存中了,可以通过 类名.class 获取Class对象;在第三阶段时,因为已经有了对象,所以可以使用 对象.getClass() 方法来获取Class对象
获取Class对象的方式:
 1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象。(全类名:包名+类名)
 		- 多用于配置文件,将全类名定义在配置文件中。读取文件,加载类。
 		- 方法实际上也是调用的CLassLoader来实现的
 2. 类名.class:通过类名的属性class获取
 		- 多用于参数的传递,有时候传参需要传一个Class对象
 3. 对象.getClass():getClass方法在Object中定义着
 		- 多用于对象获取字节码的方式

在这里插入图片描述

在这里插入图片描述
ps:同一个字节码文件(*.class)在一次程序运行中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。

3.Class对象功能:

获取功能:

  1. 获取成员变量们
Field[ ] getFields( ):获取所有public修饰的成员变量
Field getField(String name): 获取指定名字的成员变量

Field[ ] getDeclaredFields() :获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name) 
  1. 获取构造方法们
Constructor<?>[] getConstructors()  
Constructor<T> getConstructor(<?>... parameterTypes)  
	
Constructor<?>[] getDeclaredConstructors()  
Constructor<T> getDeclaredConstructor(<?>... parameterTypes) 
  1. 获取成员方法们
Method[] getMethods()  
Method getMethod(String name,<?>... parameterTypes) 

Method[] getDeclaredMethods()  
Method getDeclaredMethod(String name,<?>... parameterTypes)  

4.获取类名

String getName()

使用:

  1. 获取成员变量
Object get(Object obj)  :获取值
void set(Object obj, Object value)  : 设置值
setAccessible(true) : 暴力反射,忽略访问权限修饰符的安全检查

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 获取构造方法
创建对象
T newInstance(Object... initargs)  

如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

在这里插入图片描述
在这里插入图片描述

  1. 获取成员方法
执行方法:
Object invoke(Object obj, Object... args)  
获取方法名
Method.getName()

在这里插入图片描述
在这里插入图片描述

4.反射的体现,为什么要用反射?

看到这里会觉得反射很麻烦,没有体现出它的价值。接下来看个案例,就会一目了然了。这个案例就是写一个类,在不改变该类任何代码的前提下,可以帮助我们创建任意类的对象,并且执行其中任意方法。

步骤:

 1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件
 2. 在程序中加载读取配置文件
 3. 使用反射技术来加载类文件进入内存
 4. 创建对象
 5. 执行方法

Student类:

@NoArgsConstructor
public class Student {
    public void sleep(){
        System.out.println("睡觉");
    }
}

pro.properties配置文件:

className=com.lyp.domain.Student
methodName=sleep

ReflectTest类:

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        // 前提:不能修改该类的代码
//        Student s = new Student();
//        s.sleep();

        // 1.加载配置文件
        // 1.1 创建Properties对象
        Properties pro = new Properties();
        // 1.2 加载配置文件,转化为一个集合
        // 1.2.1 获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();//通过类加载器将字节码文件加载进内存
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        // 2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        // 3.加载该类进内存
        Class cls = Class.forName(className);
        // 4.创建对象
        Object o = cls.newInstance();
        // 5.获取方法对象
        Method method = cls.getMethod(methodName);
        // 6.执行方法
        method.invoke(o);

    }
}

运行结果:
在这里插入图片描述

将需要生成的对象的信息放在配置文件中,这样我们不需要去修改ReflectTest的代码,只需要修改配置文件中className,methodName即可;如果不使用配置文件,就需要在ReflectTest类中写死,Student s = new Student(); s.sleep();那如果想要生成别的对象每次都需要去找到ReflectTest类,修改Student为别的类。使用反射后,增加了程序的灵活性,避免将代码写死,降低了耦合性。在框架的设计思想里用到的就是反射。

  • 9
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值