版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习!

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反射机制深度剖析的更多相关文章

  1. Java反射机制剖析(四)-深度剖析动态代理原理及总结

    动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...

  2. Java反射机制剖析(三)-简单谈谈动态代理

    通过Java反射机制剖析(一)和Java反射机制剖析(二)的学习,已经对反射有了一定的了解,这一篇通过动态代理的例子来进一步学习反射机制. 1.     代理模式 代理模式就是为其他对象提供一种代理来 ...

  3. Java反射机制剖析(二)-功能以及举例

    从<java反射机制剖析(一)>的API我们看到了许多接口和类,我们能够通过这些接口做些什么呢? 从上篇API中我们能看到它能够完成下面的这些功能: 1)     获得类 A.     运 ...

  4. Java反射机制剖析(一)-定义和API

    1.     什么是Java反射机制 Java的反射机制是在程序运行时,能够完全知道任何一个类,及其它的属性和方法,并且能够任意调用一个对象的属性和方法.这种运行时的动态获取就是Java的反射机制.其 ...

  5. 【54】Java反射机制剖析

    java反射机制: 1.指的是可以于运行时加载,探知和使用编译期间完全未知的类. 2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; ...

  6. java反射机制剖析(二)— Class Loader

    上一篇博客简要的提了一下java反射机制中涉及到的一些相关知识,那么ClassLoader就是当中之中的一个.本篇博客就具体的对ClassLoader做一个相对深入的了解. 作为了解须要知道的是.事实 ...

  7. JVM的艺术-对象创建与内存分配机制深度剖析

    JVM的艺术-对象创建与内存分配机制深度剖析 引言 本章将介绍jvm的对象创建与内存分配.彻底带你了解jvm的创建过程以及内存分配的原理和区域,以及包含的内容. 对象的创建 类加载的过程 固定的类加载 ...

  8. 浅谈Java反射机制 之 获取类的字节码文件 Class.forName("全路径名") 、getClass()、class

    另一个篇:获取 类 的 方法 和 属性(包括构造函数) 先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它 ...

  9. 第28章 java反射机制

    java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...

随机推荐

  1. flex chrome浏览器调试flex程序

    flex chrome浏览器调试出现空白的解决方法: 1,为chrome安装flash player,禁用chrome自带的flash player:参考:http://www.jb51.net/ar ...

  2. Bootstrap 导航 标题栏

    Bootstrap 导航 标题栏: <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

  3. 在Windows下开发Node.js的C/C++原生扩展

    准备工作 (1)本机系统说明:本人机器为win7 64位,32位也可以. (2)软件安装: VISUAL C++ 2010 EXPRESS(Visual Studio 2010也可以): window ...

  4. Java泛型类定义,与泛型方法的定义使用

    package com.srie.testjava; public class TestClassDefine<T, S extends T> { public static void m ...

  5. 【Scala】Scala之Numbers

    一.前言 前面已经学习了Scala中的String,接着学习Scala的Numbers. 二.Numbers 在Scala中,所有的数字类型,如Byte,Char,Double,Float,Int,L ...

  6. 支持Angular 2的表格控件

    前端框架一直这最近几年特别火的一个话题,尤其是Angular 2拥有众多的粉丝.在2016年9月份Angular 2正式发布之后,大量的粉丝的开始投入到了Angular 2的怀抱.当然这其中也包括我. ...

  7. (一)Hololens Unity 开发环境搭建(Mac BOOTCAMP WIN10)

    (一)Hololens Unity 开发环境搭建(Mac BOOTCAMP WIN10) 系统要求 64位 Windows 10 除了家庭版的 都支持 ~ 64位CPU CPU至少是四核心以上~ 至少 ...

  8. Socket通信流程

    Socket通信流程 HTTP 底层就是通过socket建立连接通信管道,实现数据传输 HTTP是一个TCP的传输协议(方式),它是一个可靠,安全的协议

  9. IE6浏览器常见的bug及其修复方法

    IE6不支持min-height,解决办法使用css hack: .target { min-height: 100px; height: auto !important; height: 100px ...

  10. 基于basys2用verilog设计多功能数字钟(重写)

    话不多说先上图         前言 自从学习FPGA以来,唯一做过的完整系统就是基于basys2得多功能数字表.记得当时做的时候也没少头疼,最后用时间磨出来了一个不是很完整的小系统,当时还是产生了满 ...