Java高级特性---反射机制详解

什么是反射

反射指的是在运行状态,能动态地获取编译期未确定的类,并且对于任意的一个类或对象,都能获取及调用其所有的属性和方法。如在idea中我们创建了一个object对象,输入object. 之后idea会自动提示object的所有属性和方法。
其实本质就是Java程序到了运行的时候再去加载某一个类(.class文件),然后获取属性方法等各种信息
在这里插入图片描述

原理

Java在编译时会生成.class文件,运行时jvm会将.class文件加载进内存生成对应的class对象

什么时候用到反射

  • 我们在编写jdbc使用Class.forName加载类驱动时
  • 很多开发框架的底层都使用到了反射技术
  • idea等开发工具解析对象的类型,动态地提示属性和方法

注:但因为反射影响性能,不如直接编写的Java代码效率高,现在被运行时注解APT替代了。不过许多框架的底层都是使用反射完成的,因此反射的了解还是有必要的。

获取class对象的四种方法

  • 通过类名.class获取,不会触发类的初始化,且类会加载进jvm中
  • Class.forName()通过类的全限定名获取,会触发类的初始化
  • 实例对象.getClass()获取,会触发类的初始化
String s = "ab";
System.out.println(s.getClass());
System.out.println(Class.forName("java.lang.String"));
System.out.println(String.class);

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

获取属性、方法和构造器

获取完class对象之后,我们便可以根据这个class对象获取该类的所有属性、方法和构造器。
反射更为强大的一个地方在于能够获取用private修饰的类的属性和方法
1)首先我们先定义一个Dog类

public class Dog {
    
    public String name;
    private int age;
    
    public Dog(){   
    }
    private Dog(String name,int age){
        this.name = name;
        this.age = age;
    }
}

在此我们定义了一个public和private的属性,一个public和private的构造器,来探究反射能否获取private修饰的属性和方法。get和set方法都设置为public,在此省略。
2)获取Dog的Class对象

Class dogClass = Class.forName("reflection.Dog");
System.out.println(dogClass);

上面提到的三种获取类对象的方法都可以,在这里我们使用Class.forName()获取
3)获取所有的构造器方法

  • getConstructors() //获取所有public修饰的构造器
  • getConstructor(Class<?>)//获取public修饰的,参数类型匹配上的构造器
  • getDeclaredConstructors()//获取所以构造器
  • getDeclaredConstructor(Class<?>)//获取参数类型匹配上的构造器
    实际上获取constructor、filed和method的方法大致相同,前两种为获取public修饰的,后两种可以获取private修饰的(还需加上constructors.setAccessible(true););加了s的为获取所有,没加s的获取匹配参数的。
Constructor[] constructors = dogClass.getDeclaredConstructors();
System.out.println(Arrays.toString(constructors));

在这里插入图片描述

因为可能会存在多个构造器,我们使用了数组来保存构造器对象。我们可以发现private修饰的构造器也成功获取了。
4)获取的构造器对象创建一个类的对象实例
获取一个构造器对象,通过newInstance方法创建Dog的实例

Constructor constructor = dogClass.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Dog dog = (Dog) constructor.newInstance("mingming", 12);
System.out.println(dog);

在这里插入图片描述
5)获取属性和方法
获取属性和方法的过程大致与获取构造器的相同,这里就不再累赘了
较为重要的:method中使用invoke执行

Method method = dogClass.getDeclaredMethod("toString");
System.out.println(method.invoke(dog));

总结:反射具体啥时候会用到

说了这么多,我们大概也都知道了反射实际上就是获取class对象,然后通过这个class对象获取constructor、field、method对象。接着我们便可以通过constructor实例化对象、通过method执行方法。
但是,我们明明可以直接new一个对象,然后Object.method执行方法。为什么还要这么麻烦呢?
举个例子:
我们有Dog,Cat,Bird类,继承自Animal类,都可执行eat方法。假设我们最开始是要dog.eat,编译执行完之后需求改了,需求改了,变成了cat.eat,此时我们需要修改源代码,并且重新编译上线。这样显然非常地不灵活。而我们使用反射后,便可将信息保存在xml文件中,修改时无须重新编译。
原来:new Animal();
反射:Class.forName("Animal").newInstance()//无参构造方法
怎么样,是不是很眼熟?

Spring的IOC控制反转便是通过反射创建对象加载到容器中!因此反射的学习对于spring框架底层的理解还是很有必要的!

参考博文:
https://blog.csdn.net/huangliniqng/article/details/88554510
https://blog.csdn.net/JAck_chen0309/article/details/105427350
https://blog.csdn.net/Appleyk/article/details/77879073

感谢整理和分享!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值