Java反射机制深度剖析
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习!
Java反射机制是Java语言中一种很重要的机制,可能在工作中用到的机会不多,但是在很多框架中都有用到这种机制。我们知道Java是一门静态语言,在程序编译时变量的数据类型都已经确定,那么在Java运行时环境中,对于任意一个类,我们能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java的反射机制(Reflection)。
1、Java反射机制提供的功能
主要提供了以下几个功能:
1)在运行时判断任意一个对象所属的类;
2)在运行时构造任意一个类的对象;
3)在运行时判断任意一个类所具有的成员变量和方法;
4)在运行时调用任意一个对象的方法。
反射让Java具有了动态的特性,这种机制允许程序在运行时透过Reflection API获取任意一个已知名称的类的内部信息,包括成员变量(fields)、方法(methods)、实现的接口(interfaces)、Java语言修饰符(modifiers)以及它的父类(superclass)等等,并可在运行时改变成员变量的内容或调用方法。
2、Java Reflection API
在JDK中,提供了以下类来实现Java反射机制,这些类都位于java.lang.reflect包下:
Class类:代表一个类(注意:Class类位于java.lang包下);
Field类:代表类的成员变量;
Method类:代表类的方法;
Constructor类:代表类的构造方法;
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
通过API提供的这些类里的方法,我们可以动态获取想要的类的内部信息。
3、获取类的Class对象
Class类的实例表示正在运行的Java程序中的类和接口,每一个类都有对应的Class对象,不管一个类生成了多少个对象,这些对象都对应内存里的同一个Class对象。Class类没有public的构造方法,Class对象是在加载类时由Java虚拟机自动构建的。
有以下几种方式来获取一个类的Class对象:
1)Class类提供的静态方法:forName(String className),参数className表示所需类的完全限定名。
1 public class GetClassObject { 2 3 public static void main(String[] args) throws Exception { 4 5 Class<?> classType = Class.forName("java.lang.String"); 6 7 System.out.println(classType);//输出:class java.lang.String 8 } 9 10 }
2)运用.class语法
1 public class GetClassObject { 2 3 public static void main(String[] args) throws Exception { 4 5 Class<?> classType = String.class; 6 7 System.out.println(classType);//输出:class java.lang.String 8 } 9 10 }
3)Object类提供的方法:getClass()
1 public class GetClassObject { 2 3 public static void main(String[] args) throws Exception { 4 5 Map map = new HashMap(); 6 Class<?> classType = map.getClass(); 7 8 System.out.println(classType);//输出:class java.util.HashMap 9 } 10 11 }
4、获取类的Field(成员变量)对象
类的每一个成员变量都对应一个Field对象,Class类提供了以下方法来获取类的成员变量对应的Field对象:
1)Field getDeclaredField(String name):根据传入的变量名称返回此Class对象所表示的类或接口中声明的变量对应的Field对象。
2)Field[] getDeclaredFields():返回一个Field类型的数组,包含此Class对象所表示的类或接口中声明的所有变量的Field对象。
3)Field getField(String name):根据传入的变量名返回一个Field对象,注意与getDeclaredField(String name)不同的是,此方法返回的是public变量对应的Field对象。
4)Field[] getFields():返回一个Field类型的数组,注意与Field[] getDeclaredFields()方法不同的是,此方法返回的是所有public变量对应的Field对象。
代码示例:
1 public class GetFieldObject { 2 3 public static void main(String[] args) throws Exception { 4 5 //首先,获得String类的Class对象 6 Class<?> classType = Class.forName("java.lang.String"); 7 8 //获得String类中声明的所有成员变量的Field对象的数组 9 Field[] fields = classType.getDeclaredFields(); 10 for(Field field : fields){ 11 System.out.println(field); 12 } 13 14 System.out.println("---------------------------------------------------------------------"); 15 16 //获得String类中声明的public成员变量的Field对象的数组 17 Field[] publicFields = classType.getFields(); 18 for(Field field : publicFields){ 19 System.out.println(field); 20 } 21 22 } 23 24 }
输出结果:
从结果输出可以看出getDeclaredFields()与getFields()的区别:getDeclaredFields()返回的是所有属性的Field对象;而getFields()返回的是声明为public的属性的Field对象。
5、获取类的Method对象
类中的每一个方法都对应一个Method对象,Class类提供了以下方法来获取类中的方法对应的Method对象:
1)Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回一个Method对象,参数name表示方法名,可变参数parameterTypes是一个Class对象的数组,代表方法的参数的Class类型;
2)Method[] getDeclaredMethods():返回Method对象的一个数组,这些对象反映此Class对象所表示的类或接口声明的所有方法,包括公共、保护、默认访问和私有方法,但不包括继承的方法;
3)Method getMethod(String name, Class<?>... parameterTypes):返回一个Method对象,注意和此Method对象对应的方法是公共(public)方法;
4)Method[] getMethods():返回一个Method数组,这些对象反映此Class对象所表示的类或接口中声明的公共(public)方法(也包括父类或父接口中声明的public方法)。
代码示例:
1 public class GetMethodObject { 2 3 public static void main(String[] args) throws Exception { 4 5 //首先,获得类的Class对象 6 Class<?> classType = Class.forName("java.lang.reflect.Proxy"); 7 8 //获得类中声明的所有方法的Method对象的数组,不包括继承的父类的方法 9 Method[] methods = classType.getDeclaredMethods(); 10 for(Method method : methods){ 11 System.out.println(method); 12 } 13 14 System.out.println("----------------------------------------------------------------------"); 15 16 //获得类中的public方法的Method对象的数组,也包括继承的父类的public方法 17 Method[] publicMethods = classType.getMethods(); 18 for(Method method : publicMethods){ 19 System.out.println(method); 20 } 21 22 } 23 24 }
输出结果:
6、用反射机制调用对象的方法
Java反射机制可以在运行时动态调用类中的方法,Java Reflection API提供了我们所需的方法来完成动态调用。要想调用类中的方法首先要创建一个对象,我们通过类的Class对象来创建它所代表的类的实例,通过Class对象我们还能获得类中声明的方法的Method对象,Method类提供了Invoke方法来调用此Method对象所表示的方法。反射机制调用方法代码示例如下:
1 public class InvokeTester { 2 3 public static int add(int a, int b){ 4 return a + b; 5 } 6 7 public static String echo(String str){ 8 return "hello "+str; 9 } 10 11 12 public static void main(String[] args) throws Exception { 13 // InvokeTester invoke = new InvokeTester(); 14 // System.out.println(invoke.add(1, 2)); 15 // System.out.println(invoke.echo("tom")); 16 17 18 //用反射机制调用,首先获得类的Class对象 19 Class<?> classType = InvokeTester.class; 20 21 //通过Class对象获得一个InvokeTester类的实例 22 Object invoke = classType.newInstance(); 23 24 //获得add(int a, int b)方法的Method对象,getMethod方法的参数为方法名和方法参数类型的Class对象的数组 25 Method addMethod = classType.getMethod("add", int.class, int.class); 26 27 //通过Method类的invoke方法,调用invoke对象的add方法 28 Object result = addMethod.invoke(invoke, 1, 2); 29 30 System.out.println(result); 31 32 Method echoMethod = classType.getMethod("echo", String.class); 33 34 Object result2 = echoMethod.invoke(invoke, "Tom"); 35 36 System.out.println(result2); 37 38 } 39 }
7、用反射机制调用类的私有方法
我们知道正常情况下一个类的私有方法只允许这个类本身来调用,但使用反射机制能打破这种访问限制,让其他的类也能调用这个类的私有的方法。这种场景在实际开发中很少用到,Java也不提倡这种用法。代码示例如下:
public class Private {//定义一个私有方法private String sayHello(String name){return "hello, "+name;}}public class PrivateTest {public static void main(String[] args) throws Exception {//调用Private类的私有方法Private p = new Private();Class<?> classType = p.getClass();Method method = classType.getDeclaredMethod("sayHello", String.class);method.setAccessible(true);//取消Java访问检查,如果不设置此项则会报错 String str = (String)method.invoke(p, "Tracy");System.out.println(str);//输出:hello, Tracy }}
Method、Field、Constructor类有一个共同的父类AccessibleObject类,它提供了将反射的对象标记为在使用时取消默认Java语言访问控制检查的能力。在上面的代码中,我们在反射对象Method中设置accessible标志,它允许程序以某种通常禁止的方式来操作对象。
8、用反射机制操作类的私有变量
与前面调用类的私有方法类似,通过反射我们还能操作类的私有变量,代码示例如下:
1 public class Private2 { 2 //定义私有变量 3 private String name = "zhangsan"; 4 5 public String getName(){ 6 return name; 7 } 8 } 9 10 11 public class PrivateTest2 { 12 13 public static void main(String[] args) throws Exception { 14 //改变Private2类的私有变量的值 15 Private2 p = new Private2(); 16 17 Class<?> classType = p.getClass(); 18 19 Field field = classType.getDeclaredField("name"); 20 21 field.setAccessible(true);//取消默认java访问控制检查,Field类的父类AccessibleObject类提供的方法 22 23 field.set(p, "lisi");//Field类的set(Object obj, Object value)方法将指定对象上此Field对象表示的字段设置为指定的新值 24 25 System.out.println(p.getName());//输出:lisi 26 27 } 28 29 }
以上这些内容,我介绍了Java反射机制的中涉及的主要的几个类以及这些类的基本用法,这些类中还有很多的方法,大家可以通过查看API进行了解,用法都很简单。Java反射机制在很多框架的底层实现中有用到,还有一种很重要的设计模式也用到了反射,那就是代理模式中的动态代理,了解了动态代理模式的思想对我们研究框架有很大帮助,我会在后面的博客中介绍这些内容,欢迎大家共同探讨。
转载于:https://www.cnblogs.com/fangfuhai/p/6540105.html
Java反射机制深度剖析相关推荐
- Java反射机制剖析(一)-定义和API
1. 什么是Java反射机制 Java的反射机制是在程序运行时,能够完全知道任何一个类,及其它的属性和方法,并且能够任意调用一个对象的属性和方法.这种运行时的动态获取就是Java的反射机制.其 ...
- 月黑雁飞高,反射全知道——剖析java反射机制
文章目录 java 反射机制 反射机制概念 java反射提供的功能 反射的基本使用 反射使用步骤(获取Class对象.调用对象方法) 反射使用 例子People 获取Class的三种方法(获取一个类的 ...
- Java反射机制及API使用
原文地址 反射简单来说,就是动态加载对象,并对对象进行剖析.在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道并获取这个类的所有属性和方法. Java反射机制的作用: 在运行时判断任意 ...
- 浅谈Java反射机制 之 获取类的字节码文件 Class.forName(全路径名) 、getClass()、class...
先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性: 这种动态获取的信息以及动态调用对 ...
- Java 反射机制和动态代理是基于什么原理,了解过吗?
工作多年以及在面试中,我经常能体会到,有些面试者确实是认真努力工作,但坦白说表现出的能力水平却不足以通过面试,通常是两方面原因: 1."知其然不知其所以然". 做了多年技术,开发了 ...
- Java 反射机制你还不会?那怎么看 Spring 源码?
作者 | ewenll 责编 | 夕颜 出品 | CSDN博客 Java代码在计算机中经历的阶段:三个阶段 Person.java经过javac编译,变为Person.class文件(字节码文件),字 ...
- 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...
- Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法...
Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法 www.MyException.Cn 发布于:2012-09-15 ...
- Java反射机制分析指南
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
最新文章
- 修正版 | QPS过万,Redis大量连接超时怎么解决?
- chrome浏览器的跨域设置 Google Chrome浏览器下开启禁用缓存和js跨域限制--disable-web-security...
- 关于request取中文字符串变?的解决办法
- mac下编译安装grafana 4.2.0
- 玩转动态编译 - 高级篇:一,IL访问静态属性和字段
- 趣学python3(15)-f-string字符串
- leetcode刷题:求容器中能乘最大多少水
- 杭电1874畅通工程续
- python报表利器TableOne学习实践
- Kubernetes(K8s) 1.14.3常用操作命令
- 图-3月12日-[评委计分系统3.0-双屏专业版]又有较大的专业升级,
- MAC常用快捷键和常规操作(一)
- react native 抖音视频列表页
- WPS格式转换成Word的方法
- 怎样转换WPS格式,WPS怎么转换PPT格式
- 适合普通人的108个短视频项目:抖音手绘玩法揭秘(1)
- 华科_图形学笔记_05_初探造型技术_02
- Uaexpert操作手册
- cgal配置以及一些资料
- JAVA避免使用魔法数值
热门文章
- FCN论文-语义分割
- DenseNet实验
- python查找当前路径,在Python中查找当前终端选项卡的当前目录
- 京东下拉词框推广是什么?
- ubuntu联网_Ubuntu物联网操作系统新版发布,支持10年安全更新,镜像仅280M
- java不重复的随机数_Javascript获取不重复的随机数值
- 环信php创建群组,【PHP】接入环信创建群组和IM用户
- mysql学习day05—子查询 / CASH语句 / 连接查询
- 读书笔记∣概率论沉思录 01
- JBoss + EJB3 + MySql : 开发第一个EJB