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表示所需类的完全限定名。
public class GetClassObject {
public static void main(String[] args) throws Exception {
Class<?> classType = Class.forName("java.lang.String");
System.out.println(classType);//输出:class java.lang.String
}
}
2)运用.class语法
public class GetClassObject {
public static void main(String[] args) throws Exception {
Class<?> classType = String.class;
System.out.println(classType);//输出:class java.lang.String
}
}
3)Object类提供的方法:getClass()
public class GetClassObject {
public static void main(String[] args) throws Exception {
Map map = new HashMap();
Class<?> classType = map.getClass();
System.out.println(classType);//输出:class java.util.HashMap
}
}
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对象。
代码示例:
public class GetFieldObject {
public static void main(String[] args) throws Exception {
//首先,获得String类的Class对象
Class<?> classType = Class.forName("java.lang.String");
//获得String类中声明的所有成员变量的Field对象的数组
Field[] fields = classType.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
System.out.println("---------------------------------------------------------------------");
//获得String类中声明的public成员变量的Field对象的数组
Field[] publicFields = classType.getFields();
for(Field field : publicFields){
System.out.println(field);
}
}
}
输出结果:

从结果输出可以看出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方法)。
代码示例:
public class GetMethodObject {
public static void main(String[] args) throws Exception {
//首先,获得类的Class对象
Class<?> classType = Class.forName("java.lang.reflect.Proxy");
//获得类中声明的所有方法的Method对象的数组,不包括继承的父类的方法
Method[] methods = classType.getDeclaredMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("----------------------------------------------------------------------");
//获得类中的public方法的Method对象的数组,也包括继承的父类的public方法
Method[] publicMethods = classType.getMethods();
for(Method method : publicMethods){
System.out.println(method);
}
}
}
输出结果:

6、用反射机制调用对象的方法
Java反射机制可以在运行时动态调用类中的方法,Java Reflection API提供了我们所需的方法来完成动态调用。要想调用类中的方法首先要创建一个对象,我们通过类的Class对象来创建它所代表的类的实例,通过Class对象我们还能获得类中声明的方法的Method对象,Method类提供了Invoke方法来调用此Method对象所表示的方法。反射机制调用方法代码示例如下:
public class InvokeTester {
public static int add(int a, int b){
return a + b;
}
public static String echo(String str){
return "hello "+str;
}
public static void main(String[] args) throws Exception {
// InvokeTester invoke = new InvokeTester();
// System.out.println(invoke.add(1, 2));
// System.out.println(invoke.echo("tom"));
//用反射机制调用,首先获得类的Class对象
Class<?> classType = InvokeTester.class;
//通过Class对象获得一个InvokeTester类的实例
Object invoke = classType.newInstance();
//获得add(int a, int b)方法的Method对象,getMethod方法的参数为方法名和方法参数类型的Class对象的数组
Method addMethod = classType.getMethod("add", int.class, int.class);
//通过Method类的invoke方法,调用invoke对象的add方法
Object result = addMethod.invoke(invoke, 1, 2);
System.out.println(result);
Method echoMethod = classType.getMethod("echo", String.class);
Object result2 = echoMethod.invoke(invoke, "Tom");
System.out.println(result2);
}
}
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、用反射机制操作类的私有变量
与前面调用类的私有方法类似,通过反射我们还能操作类的私有变量,代码示例如下:
public class Private2 {
//定义私有变量
private String name = "zhangsan";
public String getName(){
return name;
}
}
public class PrivateTest2 {
public static void main(String[] args) throws Exception {
//改变Private2类的私有变量的值
Private2 p = new Private2();
Class<?> classType = p.getClass();
Field field = classType.getDeclaredField("name");
field.setAccessible(true);//取消默认java访问控制检查,Field类的父类AccessibleObject类提供的方法
field.set(p, "lisi");//Field类的set(Object obj, Object value)方法将指定对象上此Field对象表示的字段设置为指定的新值
System.out.println(p.getName());//输出:lisi
}
}
以上这些内容,我介绍了Java反射机制的中涉及的主要的几个类以及这些类的基本用法,这些类中还有很多的方法,大家可以通过查看API进行了解,用法都很简单。Java反射机制在很多框架的底层实现中有用到,还有一种很重要的设计模式也用到了反射,那就是代理模式中的动态代理,了解了动态代理模式的思想对我们研究框架有很大帮助,我会在后面的博客中介绍这些内容,欢迎大家共同探讨。
Java反射机制深度剖析的更多相关文章
- Java反射机制剖析(四)-深度剖析动态代理原理及总结
动态代理类原理(示例代码参见java反射机制剖析(三)) a) 理解上面的动态代理示例流程 a) 理解上面的动态代理示例流程 b) 代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...
- Java反射机制剖析(三)-简单谈谈动态代理
通过Java反射机制剖析(一)和Java反射机制剖析(二)的学习,已经对反射有了一定的了解,这一篇通过动态代理的例子来进一步学习反射机制. 1. 代理模式 代理模式就是为其他对象提供一种代理来 ...
- Java反射机制剖析(二)-功能以及举例
从<java反射机制剖析(一)>的API我们看到了许多接口和类,我们能够通过这些接口做些什么呢? 从上篇API中我们能看到它能够完成下面的这些功能: 1) 获得类 A. 运 ...
- Java反射机制剖析(一)-定义和API
1. 什么是Java反射机制 Java的反射机制是在程序运行时,能够完全知道任何一个类,及其它的属性和方法,并且能够任意调用一个对象的属性和方法.这种运行时的动态获取就是Java的反射机制.其 ...
- 【54】Java反射机制剖析
java反射机制: 1.指的是可以于运行时加载,探知和使用编译期间完全未知的类. 2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; ...
- java反射机制剖析(二)— Class Loader
上一篇博客简要的提了一下java反射机制中涉及到的一些相关知识,那么ClassLoader就是当中之中的一个.本篇博客就具体的对ClassLoader做一个相对深入的了解. 作为了解须要知道的是.事实 ...
- JVM的艺术-对象创建与内存分配机制深度剖析
JVM的艺术-对象创建与内存分配机制深度剖析 引言 本章将介绍jvm的对象创建与内存分配.彻底带你了解jvm的创建过程以及内存分配的原理和区域,以及包含的内容. 对象的创建 类加载的过程 固定的类加载 ...
- 浅谈Java反射机制 之 获取类的字节码文件 Class.forName("全路径名") 、getClass()、class
另一个篇:获取 类 的 方法 和 属性(包括构造函数) 先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它 ...
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
随机推荐
- flex chrome浏览器调试flex程序
flex chrome浏览器调试出现空白的解决方法: 1,为chrome安装flash player,禁用chrome自带的flash player:参考:http://www.jb51.net/ar ...
- Bootstrap 导航 标题栏
Bootstrap 导航 标题栏: <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- 在Windows下开发Node.js的C/C++原生扩展
准备工作 (1)本机系统说明:本人机器为win7 64位,32位也可以. (2)软件安装: VISUAL C++ 2010 EXPRESS(Visual Studio 2010也可以): window ...
- Java泛型类定义,与泛型方法的定义使用
package com.srie.testjava; public class TestClassDefine<T, S extends T> { public static void m ...
- 【Scala】Scala之Numbers
一.前言 前面已经学习了Scala中的String,接着学习Scala的Numbers. 二.Numbers 在Scala中,所有的数字类型,如Byte,Char,Double,Float,Int,L ...
- 支持Angular 2的表格控件
前端框架一直这最近几年特别火的一个话题,尤其是Angular 2拥有众多的粉丝.在2016年9月份Angular 2正式发布之后,大量的粉丝的开始投入到了Angular 2的怀抱.当然这其中也包括我. ...
- (一)Hololens Unity 开发环境搭建(Mac BOOTCAMP WIN10)
(一)Hololens Unity 开发环境搭建(Mac BOOTCAMP WIN10) 系统要求 64位 Windows 10 除了家庭版的 都支持 ~ 64位CPU CPU至少是四核心以上~ 至少 ...
- Socket通信流程
Socket通信流程 HTTP 底层就是通过socket建立连接通信管道,实现数据传输 HTTP是一个TCP的传输协议(方式),它是一个可靠,安全的协议
- IE6浏览器常见的bug及其修复方法
IE6不支持min-height,解决办法使用css hack: .target { min-height: 100px; height: auto !important; height: 100px ...
- 基于basys2用verilog设计多功能数字钟(重写)
话不多说先上图 前言 自从学习FPGA以来,唯一做过的完整系统就是基于basys2得多功能数字表.记得当时做的时候也没少头疼,最后用时间磨出来了一个不是很完整的小系统,当时还是产生了满 ...