深入理解Java反射机制_第1页
深入理解Java反射机制_第2页
深入理解Java反射机制_第3页
深入理解Java反射机制_第4页
深入理解Java反射机制_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、深入理解Java反射机制本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下: 一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中。这些信息主要包括: 1、这个类型的全限定名 2、这个类型的直接超类的全限定名 3、这个类型是类类型还是接口类型

2、4、这个类型的访问修饰符 5、任何直接超接口的全限定名的有序列表 6、该类型的常量池 7、字段信息 8、方法信息 9、除了常量以外的所有类变量 10、一个到class类的引用 等等(读者可以参考深入java虚拟机这本书的叙述) Class类: Class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例,该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过 Class实例来访问这些信息。比如,对于上面说到的信息Class中都有对应的方

3、法,如下: 1、getName();这个类型的全限定名 2、getSuperClass();这个类型的直接超类的全限定名 3、isInterface();这个类型是类类型还是接口类型 4、getTypeParamters();这个类型的访问修饰符 5、getInterfaces();任何直接超接口的全限定名的有序列表 6、getFields();字段信息 7、getMethods();方法信息 等等(读者可以自己参看jdk帮助文档,得到更多的信息) 二、java反射详解 反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到JVM中的类的内部信息,允

4、许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。 反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代 表的是类对象,Constructor类的构造器对象,Field类的属性对象,Method类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Cla

5、ss类中针对这三个元素的方法: 1、得到构造器的方法 Constructor getConstructor(Class params) - 获得使用特殊的参数类型的公共构造函数, Constructor getConstructors() - 获得类的所有公共构造函数 Constructor getDeclaredConstructor(Class params) - 获得使用特定参数类型的构造函数(与接入级别无关) Constructor getDeclaredConstructors() - 获得类的所有构造函数(与接入级别无关) 2、获得字段信息的方法 Field getField(St

6、ring name) - 获得命名的公共字段 Field getFields() - 获得类的所有公共字段 Field getDeclaredField(String name) - 获得类声明的命名的字段 Field getDeclaredFields() - 获得类声明的所有字段 3、获得方法信息的方法 Method getMethod(String name, Class params) - 使用特定的参数类型,获得命名的公共方法 Method getMethods() - 获得类的所有公共方法 Method getDeclaredMethod(String name, Class pa

7、rams) - 使用特写的参数类型,获得类声明的命名的方法 Method getDeclaredMethods() - 获得类声明的所有方法 应用反射的基本步骤: 1、获得你想操作的类的Class对象; 方法一:Classc=Class.forName("java.lang.String") /这种方式获得类的Class对象需要 包名.类名 方法二:对于基本数据类型可以用形如Class c=int.class或Class c=Integer.TYPE的语句 方法三:Class c=MyClass.class 2、调用Class中的方法得到你想得到的信息集合,如调用getDe

8、claredFields()方法得到类的所有属性; 3、处理第2步中得到的信息,然后进行你想做的实际操作。 反射实例: 下面我将针对类的构造器、属性和方法分别举三个例子,向大家演示一下反射的应用过程。 1、构造器 步骤为:通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例import java.lang.reflect.*; public class ConstructorDemo public ConstructorDemo() public ConstructorDemo(int a, int b) System.out.println("a="+a+&

9、quot;b="+b); public static void main(String args) try Class cls =Class.forName("包名.ConstructorDemo"); Class partypes =new Class2; partypes0 = Integer.TYPE; partypes1 =Integer.TYPE; Constructor ct=Constructor(partypes); Object arglist =new Object2; arglist0 = newInteger(37); arglist1 =

10、 newInteger(47); Object retobj = ct.newInstance(arglist); catch (Throwable e) System.err.println(e); 2、属性 步骤为:通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值import java.lang.reflect.*; public class FieldDemo1 public double d; public static void main(String args) try Class cls = Class.forName("FieldDemo1&

11、quot;); Field fld = cls.getField("d"); FieldDemo1 fobj = new FieldDemo1(); System.out.println("d = " + fobj.d); fld.setDouble(fobj, 12.34); System.out.println("d = " + fobj.d); catch (Throwable e) System.err.println(e); 3、方法 步骤为:通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法/通过使用

12、方法的名字调用方法 import java.lang.reflect.*; public class MethodDemo1 public int add(int a, int b) return a + b; public static void main(String args) try Class cls =Class.forName("MethodDemo1"); Class partypes = new Class2; partypes0 = Integer.TYPE; partypes1 = Integer.TYPE; Method meth = cls.get

13、Method("add",partypes); MethodDemo1 methobj = new MethodDemo1(); Object arglist = new Object2; arglist0 = new Integer(37); arglist1 = new Integer(47); Object retobj= meth.invoke(methobj, arglist); Integer retval = (Integer)retobj; System.out.println(Value(); catch (Throwable e) S

14、println(e); 三、java反射的应用(Hibernate) 我们在第二部分中对java反射进行了比较系统的阐述,也举了几个简单的实例,下面我们就来讨论一下java反射的具体应用。前面我们已经知 道,Java反射机制提供了一种动态链接程序组件的多功能方法,它允许程序创建和控制任何类的对象(根据安全性限制)之前,无需提前硬编码目标类。这些特 性使得反射特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。下面我们就已 Hibernate框架为例像大家阐述一下反射的重要意义。 Hibernate是一个屏蔽了JDBC,实现了OR

15、M的java框架,利用该框架我们可以抛弃掉繁琐的sql语句而是利用Hibernate中 Session类的save()方法直接将某个类的对象存到数据库中,也就是所涉及到sql语句的那些代码Hibernate帮我们做了。这时候就出现了 一个问题,Hibernate怎样知道他要存的某个对象都有什么属性呢?这些属性都是什么类型呢?如此,它在向数据库中存储该对象属性时的sql语句该怎么构造呢?解决这个问题的利器就是我们的java反射! 下面我们以一个例子来进行阐述,比如我们定义了一个User类,这个User类中有20个属性和这些属性的get和set方法,相应的在数据库中 有一个User表,这个User

16、表中对应着20个字段。假设我们从User表中提取了一条记录,现在需要将这条记录的20个字段的内容分别赋给一个 User对象myUser的20个属性,而Hibernate框架在编译的时候并不知道这个User类,他无法直接调用myUser.getXXX或者 myUser.setXXX方法,此时就用到了反射,具体处理过程如下: 1、根据查询条件构造PreparedStament语句,该语句返回20个字段的值; 2、Hibernate通过读取配置文件得到User类的属性列表list(是一个String数组)以及这些属性的类型; 3、创建myUser所属类的Class对象c;c=myUser.getCl

17、ass(); 4、构造一个for循环,循环的次数为list列表的长度; 4.1、读取listi的值,然后构造对应该属性的set方法; 4.2、判断listi的类型XXX,调用PreparedStament语句中的getXXX(i),进而得到i出字段的值; 4.3、将4.2中得到的值作为4.1中得到的set方法的参数,这样就完成了一个字段像一个属性的赋值,如此循环即可; 看到了吧,这就是反射的功劳,如果没有反射很难想象如果完成同样的功能会有多么难!但是反射也有缺点,比如性能比较低、安全性比较复杂等,这里就不在讨论这些东西,感兴趣的读者可以在网上找到答案,有很多的!要想理解反射的原理,首先要了解什

18、么是类型信息。Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。1、Class对象理解RTTI在Java中的工作原理,首先需要知道类型信息在运行时是如何表示的,这是由Class对象来完成的,它包含了与类有关的信息。Class对象就是用来创建所有“常规”对象的,Java使用Class对象来执行RTTI,即使你正在执行的是类似类型转换这样的操作。 每个类都会产生一个对应的Class对象,也就是保存在.class文件。所有类都是在对其第一次使用时,动态加载到JVM的,当程

19、序创建一个对类的静态成员的引用时,就会加载这个类。Class对象仅在需要的时候才会加载,static初始化是在类加载时进行的。public class TestMain public static void main(String args) System.out.println(XYZ.name);class XYZ public static String name = "luoxn28"static System.out.println("xyz静态块");public XYZ() System.out.println("xyz构造了&q

20、uot;); 输出结果为:类加载器首先会检查这个类的Class对象是否已被加载过,如果尚未加载,默认的类加载器就会根据类名查找对应的.class文件。想在运行时使用类型信息,必须获取对象(比如类Base对象)的Class对象的引用,使用功能Class.forName(“Base”)可以实现该目的,或者使用base.class。注意,有一点很有趣,使用功能”.class”来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象。为了使用类而做的准备工作一般有以下3个步骤: 加载:由类加载器完成,找到对应的字节码,创建一个Class对象 链接

21、:验证类中的字节码,为静态域分配空间 初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块public class Base static int num = 1;static System.out.println("Base " + num);public class Main public static void main(String args) / 不会初始化静态块Class clazz1 = Base.class;System.out.println("-");/ 会初始化Class clazz2 = Class.forName

22、("zzz.Base"); 2、类型转换前先做检查编译器将检查类型向下转型是否合法,如果不合法将抛出异常。向下转换类型前,可以使用instanceof判断。class Base class Derived extends Base public class Main public static void main(String args) Base base = new Derived();if (base instanceof Derived) / 这里可以向下转换了System.out.println("ok");else System.out.pr

23、intln("not ok"); 3、反射:运行时类信息如果不知道某个对象的确切类型,RTTI可以告诉你,但是有一个前提:这个类型在编译时必须已知,这样才能使用RTTI来识别它。Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员。这样的话就可以使用Contructor创建新的对象,用get()和set()方法获取和修改类中与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFi

24、elds()、getMethods()和getConstructors()等许多便利的方法,以返回表示字段、方法、以及构造器对象的数组,这样,对象信息可以在运行时被完全确定下来,而在编译时不需要知道关于类的任何事情。反射机制并没有什么神奇之处,当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类。因此,那个类的.class对于JVM来说必须是可获取的,要么在本地机器上,要么从网络获取。所以对于RTTI和反射之间的真正区别只在于: RTTI,编译器在编译时打开和检查.class文件 反射,运行时打开和检查.class文件public class Person

25、 implements Serializable private String name;private int age;/ get/set方法public static void main(String args) Person person = new Person("luoxn28", 23);Class clazz = person.getClass();Field fields = clazz.getDeclaredFields();for (Field field : fields) String key = field.getName();PropertyDe

26、scriptor descriptor = new PropertyDescriptor(key, clazz);Method method = descriptor.getReadMethod();Object value = method.invoke(person);System.out.println(key + ":" + value); 以上通过getReadMethod()方法调用类的get函数,可以通过getWriteMethod()方法来调用类的set方法。通常来说,我们不需要使用反射工具,但是它们在创建动态代码会更有用,反射在Java中用来支持其他特性的

27、,例如对象的序列化和JavaBean等。4、动态代理代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色。Java的动态代理比代理的思想更前进了一步,它可以动态地创建并代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的策略。以下是一个动态代理示例:接口和实现类:public interface Interface void doSomething();void somethingElse(String arg);public class RealObject implements Interface public void doSomething() System.out.println("doSomething.");public void somethingElse(String arg) System.out.println

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论