学学Java基础——Java反射

Java反射是什么

Java反射是一种在运行时动态获取和操作类或对象的信息和功能的机制。它可以让我们在不知道具体类型的情况下,创建对象,访问属性,调用方法,甚至修改类的结构。Java反射的核心是Class类,它代表了一个类的所有信息,包括构造方法,字段,方法等。我们可以通过Class对象来实现反射的各种功能。

Java反射的优点是可以增加程序的灵活性和扩展性,比如可以实现动态代理,依赖注入,框架开发等。Java反射的缺点是会降低程序的性能和安全性,比如会消耗更多的内存和CPU资源,以及破坏类的封装性和访问控制。

Java反射为什么出现

原因1,Java在编译时就确定了类和对象的类型,这样可以提高程序的性能和安全性,但也限制了程序的灵活性和扩展性。如果我们想要在运行时动态地加载和使用某些类或对象,而不是在编译时就写死在代码中,那么就需要一种机制来实现这个目的。Java反射就是这样一种机制,它可以让我们在运行时获取类或对象的信息,并且根据需要进行操作。

原因2,Java是一种面向对象的语言,也就是说,它把程序中的数据和行为封装成为对象,并且通过继承和多态来实现代码的复用和扩展。但是,在某些情况下,我们可能需要对对象进行更深入的操作,比如访问私有属性或方法,或者修改类的结构等。这些操作在正常情况下是不允许或者不方便的,因为它们会破坏类的封装性和访问控制。Java反射就可以让我们突破这些限制,通过反射API来实现这些操作。

原因3,Java是一种跨平台的语言,它可以运行在不同的操作系统和硬件环境上。但是,在不同的平台上,可能存在一些特定的功能或资源,比如文件系统,网络通信,图形界面等。这些功能或资源可能需要使用特定的类库或接口来访问或控制。如果我们想要编写一个通用的程序,而不是针对每个平台都写一个专门的版本,那么就需要一种机制来实现这个目的。Java反射就是这样一种机制,它可以让我们在运行时根据平台的特性来加载和使用相应的类库或接口。等等等等。。

所以Java反射出现的原因就是为了增加程序的灵活性和扩展性,在运行时动态地获取和操作类或对象。当然,Java反射也有一些缺点和风险,在使用Java反射时,我们需要权衡利弊,并且遵循一些规范和原则。

Java反射内容

反射的使用

第一步,获取目标类的Class对象实例。

有三种方式。Class.forName(“完整类名带包名”),类型.class,对象.getClass(),下面默认我创建了Person的类,而且异常我都默认抛出了,没使用try-catch拦截。

//使用Class.forName(“完整类名带包名”)静态方法。这种方式适合在运行时通过字符串来指定类名。
Class.forName("Person");

//使用任何类型.class语法。这种方式适合在编译时就知道要操作的类。
Class<Person> personClass = Person.class;

//使用对象.getClass()方法。这种方式适合已经有目标类的对象实例。
Person person = new Person();
person.getClass();

第二步,创建目标类的对象实例。

Class对象的newInstance()方法。  使用Class对象的getConstructor()方法获取目标类的某个构造方法,然后使用该构造方法的newInstance()方法传入相应的参数来创建对象实例。

//使用Class对象的newInstance()方法。这种方式会调用目标类的无参构造方法,
//所以要求目标类必须有无参构造方法。
Person newInstance = personClass.newInstance();
//使用Class对象的getConstructor()方法获取目标类的某个构造方法,
//然后使用该构造方法的newInstance()方法传入相应的参数来创建对象实例。
//这种方式可以选择任意的构造方法,但是要求构造方法是可访问的(public或同包)。
//    getConstructor()方法的作用是返回一个Constructor对象,该对象反映了这个Class对象所代表的类的指定公共构造器。
//    getConstructor()方法有一个参数,parameterTypes,它是一个Class对象数组,它们按照声明的顺序标识构造函数的形式参数类型。
//    例如,如果我们想要获取Person类的一个带有Integer与String参数的公共构造器,我们可以这样写:

Class[] parameterTypes = new Class[] {Integer.class,String.class};
Constructor<Person> personClassConstructor = personClass.getConstructor(parameterTypes);

第三步,获取和操作目标类的属性或方法。

1,获取公共的属性或方法,使用getField()或getMethod()方法得到属性或方法,然后使用该属性或方法的get()或invoke()方法

//(只能获取公共的)使用Class对象的getField()或getMethod()方法获取目标类的某个公共属性或方法,
// 然后使用该属性或方法的get()或invoke()方法传入对象实例和相应的参数来读取或调用该属性或方法。

        Field alies = personClass.getField("alies");
        String o = (String) alies.get(newInstance1);
        System.out.println(o);

        Method see = personClass.getMethod("see");
        see.invoke(newInstance1);

  2,getDeclaredField()或getDeclaredMethod()方法得到属性或方法,并且使用setAccessible(true)方法来取消访问检查。然后使用该属性或方法的get()或invoke()方法

//使用Class对象的getDeclaredField()或getDeclaredMethod()方法获取目标类的某个任意属性或方法,
//然后使用该属性或方法的setAccessible(true)方法取消访问检查,然后使用该属性或方法的get()或invoke()方法传入对象实例和相应的参数来读取或调用该属性或方法。
        Field name = personClass.getDeclaredField("name");
        name.setAccessible(true);
        String n = (String) name.get(newInstance1);
        System.out.println(n);

        Method eat = personClass.getDeclaredMethod("eat");
        eat.setAccessible(true);
        eat.invoke(newInstance1);

反射在哪里使用了

在动态代理中使用了。通过反射可以动态地生成一个代理对象,该对象可以实现某个接口或继承某个类,并且可以在运行时拦截或增强目标对象的方法调用。例如,JDK动态代理和CGLIB动态代理都是基于反射实现的。

在Spring框架的依赖注入也是通过反射动态地给对象的属性或方法赋值或注入其他对象,而不需要在代码中显式地调用set方法或构造方法。例如,Spring框架就是基于反射实现了依赖注入的功能。

还有配置解析方面通过反射可以动态地根据配置文件或注解来创建和初始化对象,并且可以根据需要修改配置而不影响代码。例如,Hibernate框架,MyBatis框架就是基于反射实现了配置文件的解析。等等等等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值