Java十分钟精通反射机制原理
什么是反射?
反射机制是在运行状态中,它为Java提供一种“操作对象”的能力,在运行状态下,通过Class文件对象,可以调用到任何类里面的属性、方法、以及构造方法,包括私有的,所有的类在反射机制面前都是透明的
自己的概括:通过Class文件对象可以看到这个类里面的所有东西,并且可以使用和修改
反射的前提是获取Class文件对象((字节码对象),那么一共有三种方式获取:
- Class.forName(“全类名”) ----通过Class类的静态方法(最常用)
- 类名.class
- 对象.getClass()
//方式1:获取字节码对象,Class.forName("全类名") Class cla1 = Class.forName("Study01.Person"); //方式2: 类名.Class Class cla2 = Person.class; //方式3:对象.getClass(); Person per = new Person(); 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,就是看反射能不能得到里面的值)
public class Person { private String name; //名字 private int age = 18; //年龄 public int ID = 123; //身份证 public String Sex; //性别 @Override public String toString(){ return "姓名"+name+"年龄:"+age+"ID:"+ID+"性别:"+Sex; } }
测试类:
public class Test { public static void main(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类:
public class Person { private String name; //名字 private int age = 18; //年龄 public int ID = 123; //身份证 public String Sex ; //性别 //构造: public Person() {} public Person(String name, int age, int ID, String sex) { this.name = name; this.age = age; this.ID = ID; Sex = sex; } //无参公有方法: public void eat(){ System.out.println("我会吃饭"); } //有参公有方法: public void eat(String food){ System.out.println("我在吃:"+food); } //有参私有方法 private void play(String name){ System.out.println(name+"在玩"); } }
测试类:
public class Test { public static void main(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 = new Person(); //通过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方法↓-----
public void Test02.Person.eat(java.lang.String)
方法名:eat
public void Test02.Person.eat()
方法名:eat
public final void java.lang.Object.wait() throws java.lang.InterruptedException
方法名:wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
方法名:wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
方法名:wait
public boolean java.lang.Object.equals(java.lang.Object)
方法名:equals
public java.lang.String java.lang.Object.toString()
方法名:toString
public native int java.lang.Object.hashCode()
方法名:hashCode
public final native java.lang.Class java.lang.Object.getClass()
方法名:getClass
public final native void java.lang.Object.notify()
方法名:notify
public final native void java.lang.Object.notifyAll()
方法名:notifyAll
小结:
以上就是小应学长对反射的理解和方法的应用(当然还有很多方法,这里就不一一举例,大家可以查看官网文档和其他技术博客开学习),其实我刚开始接触反射的时候也很难理解反射的概念,也是通过大量的视频和查看其他的博客来结合每个人的见解,这篇文章也有很多不足之处,欢迎大家批评指正,一起共同进步。
当然反射也有缺点(查阅其他博客的知识):
- 性能问题: 使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
- 反射会模糊程序内部逻辑:一般开发人员希望在源代码中看到程序内部的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。其实反射代码比直接的代码更复杂。
到此这篇关于Java十分钟精通反射机制原理的文章就介绍到这了,更多相关Java 反射机制内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
原文出处:https://blog.csdn.net/m0_57310550/article/details/123292714
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18