0


Java真的不难(二十)反射机制

反射:

首先,反射是框架的灵魂,Java框架底层都是用反射机制+xml配置等来实现的。

什么是反射?
反射机制是在运行状态中,它为Java提供一种“操作对象”的能力,在运行状态下,通过Class文件对象,可以调用到任何类里面的属性、方法、以及构造方法,包括私有的,所有的类在反射机制面前都是透明的

自己的概括:通过Class文件对象可以看到这个类里面的所有东西,并且可以使用和修改
在这里插入图片描述
反射的前提是获取Class文件对象((字节码对象),那么一共有三种方式获取:

  1. Class.forName(“全类名”) ----通过Class类的静态方法(最常用)
  2. 类名.class
  3. 对象.getClass()
//方式1:获取字节码对象,Class.forName("全类名")
Class cla1= Class.forName("Study01.Person");//方式2: 类名.Class
Class cla2= Person.class;//方式3:对象.getClass();
Person per =newPerson();
Class cla3= per.getClass();//这三个class对象都是由Person这个类生成的//那么我们看一下这三个字节码对象是不是同一个:

System.out.println(cla1==cla2);
System.out.println(cla2==cla3);//输出结果:  两个true

结论:

  • 字节码对象在类加载的时候就产生,并且只有一个
  • 无论哪种方式获取字节码对象都是同一个字节码对象

通过反射来获取类中的属性:

获取到Class字节码对象后,我们就可以通过字节码对象来获取到我们想要获取的类的属性、方法、构
造方法、以及private修饰的。

部分Class方法:(全部的可以查阅官方文档)
查阅地址:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html

在这里插入图片描述
Demo演示:
1、建一个Person类,里面有两个public和两个private的属性(不设置构造和get/set,就是看反射能不能得到里面的值)

publicclassPerson{private String name;//名字privateint age =18;//年龄publicint ID =123;//身份证public String Sex;//性别@Overridepublic String toString(){return"姓名"+name+"年龄:"+age+"ID:"+ID+"性别:"+Sex;}}

测试类:

publicclassTest{publicstaticvoidmain(String[] args)throws ClassNotFoundException {//获取Class文件对象,用最常用的通过Class类的静态方法
        Class per= Class.forName("Test01.Person");//这里是传入全路径!!从最外层的包名开始!//使用getFields()方法获取全部被public修饰的属性(方法上面的截图有)//并且返回的是Field类型的数组
        Field fields[]= per.getFields();for(Field field:fields){
            System.out.println(field);}}}

输出:

我们成功的获取到了Person类中全部public属性在这里插入图片描述
2、也可以获取全部的属性,包括私有的:(其他代码就不重写啦)

for(Field field : per.getDeclaredFields()){
            System.out.println(field);}

输出:
在这里插入图片描述

3、获取公有的属性,并且修改这个值:

    
    Field f = per.getField("Sex");
    System.out.println(f);//获取一个对象:
    Object obj = per.getConstructor().newInstance();//修改值:
    f.set(obj,"男");
    Person p =(Person)obj;
    
    System.out.println(p.Sex);

输出:

在这里插入图片描述

4、获取私有的属性,并且修改这个值:
这里把上面修改公有属性的值也连起来:

   
        Person p =(Person)obj;//获取公有字段并调用,并修改
        Field f = per.getField("Sex");//获取一个对象:
        Object obj = per.getConstructor().newInstance();
        f.set(obj,"男");//将Sex的属性修改成了 男//调用私有的属性,并修改
        f = per.getDeclaredField("name");//在访问私有的属性的值之前,先要设置运行访问↓//在访问之前忽略访问权限的检查,叫暴力反射
        f.setAccessible(true);
        f.set(obj,"张三");
        System.out.println("Person里面的信息是:"+p.toString());}}

输出:
在这里插入图片描述

通过反射来获取类中的方法(公有、私有、构造):

Person类:

publicclassPerson{private String name;//名字privateint age =18;//年龄publicint ID =123;//身份证public String Sex ;//性别//构造:publicPerson(){}publicPerson(String name,int age,int ID, String sex){this.name = name;this.age = age;this.ID = ID;
        Sex = sex;}//无参公有方法:publicvoideat(){
        System.out.println("我会吃饭");}//有参公有方法:publicvoideat(String food){
        System.out.println("我在吃:"+food);}//有参私有方法privatevoidplay(String name){
        System.out.println(name+"在玩");}}

测试类:

publicclassTest{publicstaticvoidmain(String[] args)throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//获取到Person以及父类Object里面的public方法:
        System.out.println("-----获取到Person以及父类Object里面的public方法↓-----");for(Method method : Person.class.getMethods()){
            System.out.println(method);
            System.out.println("方法名:"+ method.getName());}//获取到Person里面的方法,包括私有
        System.out.println("-----获取到Person里面的方法,包括私有↓-----");for(Method method:Person.class.getDeclaredMethods()){
            System.out.println(method.getName()+"  ");}//按照方法名获取到Person中的eat方法:
        System.out.println("-----根据方法名获取到Person类中的eat方法↓-----");
        Method earMethod1 = Person.class.getMethod("eat");
        Person per =newPerson();//通过invoke(Object,param...)来调用指定的方法
        earMethod1.invoke(per);//使用反射调用有参方法;
        System.out.println("-----使用反射调用有参方法(传入参数)↓-----");
        Method earMethod2 = Person.class.getMethod("eat",String.class);
        earMethod2.invoke(per,"牛肉");//通过暴力反射获取到私有的play方法:
        System.out.println("-----通过暴力反射获取到私有的play方法传入参数)↓-----");
        Method earMethod3 = Person.class.getDeclaredMethod("play", String.class);//在访问私有的属性的方法之前,先要设置运行访问
        earMethod3.setAccessible(true);
        earMethod3.invoke(per,"小王");}

输出:

-----获取到Person以及父类Object里面的public方法↓-----publicvoid Test02.Person.eat(java.lang.String)
方法名:eat
publicvoid Test02.Person.eat()
方法名:eat
publicfinalvoid java.lang.Object.wait()throws java.lang.InterruptedException
方法名:wait
publicfinalvoid java.lang.Object.wait(long,int)throws java.lang.InterruptedException
方法名:wait
publicfinalnativevoid java.lang.Object.wait(long)throws java.lang.InterruptedException
方法名:wait
publicboolean java.lang.Object.equals(java.lang.Object)
方法名:equals
public java.lang.String java.lang.Object.toString()
方法名:toString
publicnativeint java.lang.Object.hashCode()
方法名:hashCode
publicfinalnative java.lang.Class java.lang.Object.getClass()
方法名:getClass
publicfinalnativevoid java.lang.Object.notify()
方法名:notify
publicfinalnativevoid java.lang.Object.notifyAll()
方法名:notifyAll

-----获取到Person里面的方法,包括私有↓-----
eat  
eat  
play  

-----根据方法名获取到Person类中的eat方法↓-----
我会吃饭

-----使用反射调用有参方法(传入参数)↓-----
我在吃:牛肉

-----通过暴力反射获取到私有的play方法传入参数)↓-----
小王在玩

Process finished with exit code 0

小结:

以上就是小应学长对反射的理解和方法的应用(当然还有很多方法,这里就不一一举例,大家可以查看官网文档和其他技术博客开学习),其实我刚开始接触反射的时候也很难理解反射的概念,也是通过大量的视频和查看其他的博客来结合每个人的见解,这篇文章也有很多不足之处,欢迎大家批评指正,一起共同进步。

当然反射也有缺点(查阅其他博客的知识):

  • 性能问题: 使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
  • 反射会模糊程序内部逻辑:一般开发人员希望在源代码中看到程序内部的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。其实反射代码比直接的代码更复杂。

在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_57310550/article/details/123292714
版权归原作者 热爱飞行的小应学长 所有, 如有侵权,请联系我们删除。

“Java真的不难(二十)反射机制”的评论:

还没有评论