信息发布软件,b2b软件,广告发布软件
标题: 详解reflect Java的反射机制多方法实例教程 [打印本页]
作者: 宣传软件 时间: 2016-9-24 08:39
标题: 详解reflect Java的反射机制多方法实例教程
一、java的反射机制浅谈
最近研究java研究得很给力,主要以看博文为学习方式。以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出。受到各位指教之处,如若让小生好好感动,说不定会请各位吃饭哦!
1.何谓反射机制
根据网文,java中的反射机制可以如此定义:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.反射机制如何实现
谈到反射机制,最诱人的莫过于“动态”二字了。接触过C语言的童鞋们都知道,C语言中也有个和“动态”搭上边的函数:malloc()函数。其实这里的两个动态是一个意思,都指的是非编译时处理,抑或运行时处理。这种机制,可以让程序的弹性增加不少,因为借由此机制,客户可以在程序运行时改变一些他关心的性质:分配内存(当然他可能 完全不知道这么做了),调用某个类(当然他还是被蒙在鼓里)等。
下面我们就聊聊java中动态机制是如何实现的。
上一篇文章中提到了java的类的加载问题,但没有更深入地解释其运行机制,在这里就先谈谈这个问题。
首先不得不提到的是java.lang.Class这个类。
有这么一段话:
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。
也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。
而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为
Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。
获取Class对象有三种方式:
1.通过Object类的getClass()方法。例如:
Class c1 = new String("").getClass();
2.通过Class类的静态方法——forName()来实现:
Class c2 = Class.forName("MyObject");
3.如果T是一个已定义的类型的话,在java中,它的.class文件名:T.class就代表了与其匹配的Class对象,例如:
Class c3 = Manager.class;
Class c4 = int.class;
Class c5 = Double[].class;
这里需要解释一下3:请记住一句话,java中,一切皆对象。也就是说,基本类型int float 等也会在jvm的内存池像其他类型一样中生成
一个Class对象。而数组等组合型数据类型也是会生成一个Class对象的,而且更令人惊讶的是,java中数组的本来面目其实就是某个类,惊讶
中的惊讶是,含有相同元素的相同维数的数组还会共同享用同一个Class对象!其实根据我的臆想,数组的length性质应该就保存在这个Class
对象里面。
Class类中存在以下几个重要的方法:
1.getName()
一个Class对象描述了一个特定类的特定属性,而这个方法就是返回String形式的该类的简要描述。由于历史原因,对数组的Class对象
调用该方法会产生奇怪的结果。
2.newInstance()
该方法可以根据某个Class对象产生其对应类的实例。需要强调的是,它调用的是此类的默认构造方法。例如:
MyObject x = new MyObject();
MyObject y = x.getClass().newInstance();
3.getClassLoader()
返回该Class对象对应的类的类加载器。
4.getComponentType()
该方法针对数组对象的Class对象,可以得到该数组的组成元素所对应对象的Class对象。例如:
int[] ints = new int[]{1,2,3};
Class class1 = ints.getClass();
Class class2 = class1.getComponentType();
而这里得到的class2对象所对应的就应该是int这个基本类型的Class对象。
5.getSuperClass()
返回某子类所对应的直接父类所对应的Class对象。
6.isArray()
判定此Class对象所对应的是否是一个数组对象。
好啦,现在对Class这个类应该有了一个大致的了解,下面就给出一个反射机制的典型例子供各位分析:
[java] view plain copy
print?
- import java.lang.reflect.Array;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
-
-
- /**
- * Java Reflection Cookbook
- *
- * @author Michael Lee
- * @since 2006-8-23
- * @version 0.1a
- */
-
- public class Reflection {
- /**
- * 得到某个对象的公共属性
- *
- * @param owner, fieldName
- * @return 该属性对象
- * @throws Exception
- *
- */
- public Object getProperty(Object owner, String fieldName) throws Exception {
- Class ownerClass = owner.getClass();
-
- Field field = ownerClass.getField(fieldName);
-
- Object property = field.get(owner);
-
- return property;
- }
-
- /**
- * 得到某类的静态公共属性
- *
- * @param className 类名
- * @param fieldName 属性名
- * @return 该属性对象
- * @throws Exception
- */
- public Object getStaticProperty(String className, String fieldName)
- throws Exception {
- Class ownerClass = Class.forName(className);
-
- Field field = ownerClass.getField(fieldName);
-
- Object property = field.get(ownerClass);
-
- return property;
- }
-
-
- /**
- * 执行某对象方法
- *
- * @param owner
- * 对象
- * @param methodName
- * 方法名
- * @param args
- * 参数
- * @return 方法返回值
- * @throws Exception
- */
- public Object invokeMethod(Object owner, String methodName, Object[] args)
- throws Exception {
-
- Class ownerClass = owner.getClass();
-
- Class[] argsClass = new Class[args.length];
-
- for (int i = 0, j = args.length; i < j; i++) {
- argsClass = args.getClass();
- }
-
- Method method = ownerClass.getMethod(methodName, argsClass);
-
- return method.invoke(owner, args);
- }
-
-
- /**
- * 执行某类的静态方法
- *
- * @param className
- * 类名
- * @param methodName
- * 方法名
- * @param args
- * 参数数组
- * @return 执行方法返回的结果
- * @throws Exception
- */
- public Object invokeStaticMethod(String className, String methodName,
- Object[] args) throws Exception {
- Class ownerClass = Class.forName(className);
-
- Class[] argsClass = new Class[args.length];
-
- for (int i = 0, j = args.length; i < j; i++) {
- argsClass = args.getClass();
- }
-
- Method method = ownerClass.getMethod(methodName, argsClass);
-
- return method.invoke(null, args);
- }
-
-
-
- /**
- * 新建实例
- *
- * @param className
- * 类名
- * @param args
- * 构造函数的参数
- * @return 新建的实例
- * @throws Exception
- */
- public Object newInstance(String className, Object[] args) throws Exception {
- Class newoneClass = Class.forName(className);
-
- Class[] argsClass = new Class[args.length];
-
- for (int i = 0, j = args.length; i < j; i++) {
- argsClass = args.getClass();
- }
-
- Constructor cons = newoneClass.getConstructor(argsClass);
-
- return cons.newInstance(args);
-
- }
-
-
-
- /**
- * 是不是某个类的实例
- * @param obj 实例
- * @param cls 类
- * @return 如果 obj 是此类的实例,则返回 true
- */
- public boolean isInstance(Object obj, Class cls) {
- return cls.isInstance(obj);
- }
-
- /**
- * 得到数组中的某个元素
- * @param array 数组
- * @param index 索引
- * @return 返回指定数组对象中索引组件的值
- */
- public Object getByArray(Object array, int index) {
- return Array.get(array,index);
- }
- }
例子的解释就免了,因为读代码加上自己理解是最好的程序员学习方式。另外,此代码来源为互联网。
好啦,就到这里了。当你知道了java的反射机制后,以后当你接触到java的动态代理时就不会像我一样茫然了。好啦,谢谢围观!
作者: 宣传软件 时间: 2016-9-24 08:40
多方法实例教程2
一、类型识别的两种方式:
首先了解一下“运行时类型识别”(Run-time Type Identification, RTTI)主要有两种方式,
第一种:是我们在一次编译时和运行时已经知道了所有的类型。
第二种:是我们在整项目分模块的编译,在运行时可以对新加入的模块进行动态的编译。(在动态编译模块之前还不知道被编译code的类型。) 这就是下面要接受的,功能强大的“反射”机制。
二、认识“Class对象”:
要理解RTTI(运行时类型识别)在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由“Class对象”完成的,它包含了与类有关的信息。
类是程序的重要组成部分(类的属性,方法以及它的一些特性,在这里我就不做赘述了。),每个类都有一个Class对象,每当编写并编译了一个新类就会产生一个Class对象,它被保存在一个与你所创建的新类同名的.class文件中。那么在程序运行时,当我们想生成这个类的对象时(实例化这个类),运行这个程序的Java虚拟机(JVM)就会这样做:
首先会从加载所创新类的.class文件,
然后确认这个新类的Class对象是否已经加载,如果尚未加载,JVM就会根据类名查找.class文件,并将其载入,一旦这个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
一般的RTTI形式包括三种:
1.传统的类型转换。如“(Apple)Fruit”,由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常。
2.通过Class对象来获取对象的类型。如
[code="java"] Class c = Class.forName(“Apple”);
Object o = c.newInstance();
3.通过关键字instanceof或Class.isInstance()方法来确定对象是否属于某个特定类型的实例,准确的说,应该是instanceof / Class.isInstance()可以用来确定对象是否属于某个特定类及其所有基类的实例,这和equals() / ==不一样,它们用来比较两个对象是否属于同一个类的实例,没有考虑继承关系。[enxtpage]
三、反射
如果不知道某个对象的类型,可以通过RTTI来获取,但前提是这个类型在编译时必须已知,这样才能使用RTTI来识别。即在编译时,编译器必须知道所有通过RTTI来处理的类。
使用反射机制可以不受这个限制,它主要应用于两种情况:
第一种情况,是“基于构件的编程”这种编程方式中,将使用某种基于快速应用开发(RAD)的应用构建工具来构建项目。这是现在最常见的可视化编程方法,通过代表不同组件的图标拖动到图板上,然后设置”构件“(组件)的属性值来配置它们来创建程序。要做到这种配置编程,就必须要求构件都是可实例化的,并且要暴露其部分信息,使得程序员可以读取和设置构件的值和状态。当处理GUI时间的构件时还必须暴露相关方法的事件处理细节,以便RAD环境帮助程序员覆盖这些处理事件的方法。在这里,就要用到反射的机制来检查可用的方法并返回方法实体对象。Java通过JavaBeans提供了基于构件的编程架构。
第二种情况,在运行时获取类的信息的另外一个动机,就是希望能够提供在跨网络的远程平台上创建和运行对象的能力。这被成为远程调用(RMI),它允许一个Java程序将对象分步在多台机器上,这种分步能力将帮助开发人员执行一些需要进行大量计算的任务,充分利用计算机资源,提高运行速度。
Class类支持反射,是在java.lang.reflect中包含了Field/Method/Constructor类,每个类都实现了Member接口。这些类型的对象都是由JVM在运行时创建的,用来表示未知类里对应的成员。如可以用Constructor类创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。同时,还可以调用getFields()、getMethods()、getConstructors()等方法来返回表示字段、方法以及构造器的对象数组。这样,未知的对象的类信息在运行时就能被完全确定下来,而在编译时不需要知道任何信息。
另外,RTTI有时能解决效率问题。当程序中使用多态给程序的运行带来负担的时候,可以使用RTTI编写一段代码来提高效率。
作者: 宣传软件 时间: 2016-9-24 08:41
多方法实例教程3
反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧!
一,先看一下反射的概念:
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
看概念很晕的,继续往下看。
二,反射机制的作用:
1,反编译:.class-->.java
2,通过反射机制访问java对象的属性,方法,构造方法等;
这样好像更容易理解一些,下边我们具体看怎么实现这些功能。
三,在这里先看一下sun为我们提供了那些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
很多反射中的方法,属性等操作我们可以从这四个类中查询。还是哪句话要学着不断的查询API,那才是我们最好的老师。
四,具体功能实现:
1,反射机制获取类有三种方法,我们来获取Employee类型
[java] view plain copy
print?
//第一种方式:
Classc1 = Class.forName("Employee");
//第二种方式:
//java中每个类型都有class 属性.
Classc2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employeee = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
2,创建对象:获取类以后我们来创建它的对象,利用newInstance:
[java] view plain copy
print?
Class c =Class.forName("Employee");
//创建此Class 对象所表示的类的一个新实例
Objecto = c.newInstance(); //调用了Employee的无参数构造方法.
3,获取属性:分为所有的属性和指定的属性:
a,先看获取所有的属性的写法:
[java] view plain copy
print?
//获取整个类
Class c = Class.forName("java.lang.Integer");
//获取所有的属性?
Field[] fs = c.getDeclaredFields();
//定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
//通过追加的方法,将每个属性拼接到此字符串中
//最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
}
sb.append("}");
System.out.println(sb);
b,获取特定的属性,对比着传统的方法来学习:
[java] view plain copy
print?
public static void main(String[] args) throws Exception{
<span style="white-space:pre"> </span>//以前的方式:
/*
User u = new User();
u.age = 12; //set
System.out.println(u.age); //get
*/
//获取类
Class c = Class.forName("User");
//获取id属性
Field idF = c.getDeclaredField("id");
//实例化这个类赋给o
Object o = c.newInstance();
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
idF.set(o, "110"); //set
//get
System.out.println(idF.get(o));
}
4,获取方法,和构造方法,不再详细描述,只来看一下关键字:
方法关键字
含义
getDeclaredMethods()
获取所有的方法
getReturnType()
获得方法的放回类型
getParameterTypes()
获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法
构造方法关键字
含义
getDeclaredConstructors()
获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法
父类和父接口
含义
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口
这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
五,反射加配置文件,使我们的程序更加灵活:
在设计模式学习当中,学习抽象工厂的时候就用到了反射来更加方便的读取数据库链接字符串等,当时不是太理解,就照着抄了。看一下.NET中的反射+配置文件的使用:
当时用的配置文件是app.config文件,内容是XML格式的,里边填写链接数据库的内容:
[html] view plain copy
print?
<configuration>
lt;appSettings>
<add key="" value=""/>
lt;/appSettings>
</configuration>
反射的写法:
[csharp] view plain copy
print?
assembly.load("当前程序集的名称").CreateInstance("当前命名空间名称".要实例化的类名);
这样的好处是很容易的方便我们变换数据库,例如我们将系统的数据库从SQL Server升级到Oracle,那么我们写两份D层,在配置文件的内容改一下,或者加条件选择一下即可,带来了很大的方便。
当然了,JAVA中其实也是一样,只不过这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配置文件的内容我们可以改,这样使我们的代码灵活了很多!
综上为,JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。
作者: 宣传软件 时间: 2016-9-24 08:43
本帖最后由 宣传软件 于 2016-9-24 08:45 编辑
实例教程4
本文以实例形式详细讲述了Java的反射机制,是Java程序设计中重要的技巧。分享给大家供大家参考。具体分析如下:
首先,Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。 Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
1. 一个简单的例子
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName("java.util.Stack"); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m.toString()); } catch (Throwable e){ System.err.println(e); } } }
它的结果输出为:
public synchronized java.lang.Object java.util.Stack.pop()public java.lang.Object java.util.Stack.push(java.lang.Object)public boolean java.util.Stack.empty()public synchronized java.lang.Object java.util.Stack.peek()public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
2.开始使用 Reflection
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName("java.lang.String");
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class; 或者 Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
Class c = Class.forName("java.lang.String"); Method m[] = c.getDeclaredMethods(); System.out.println(m[0].toString());
它将以文本方式打印出 String 中定义的第一个方法的原型。
在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。
模拟 instanceof 操作符
得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:
class S { } public class IsInstance { public static void main(String args[]) { try { Class cls = Class.forName("S"); boolean b1 = cls.isInstance(new Integer(37)); System.out.println(b1); boolean b2 = cls.isInstance(new S()); System.out.println(b2); } catch (Throwable e) { System.err.println(e); } } }
在这个例子中创建了一个S 类的 Class 对象,然后检查一些对象是否是S的实例。Integer(37) 不是,但 new S()是。
3.找出类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:
import java.lang.reflect.*; public class Method1 { private int f1(Object p, int x) throws NullPointerException { if (p == null) throw new NullPointerException(); return x; } public static void main(String args[]) { try { Class cls = Class.forName("Method1"); Method methlist[] = cls.getDeclaredMethods(); for (int i = 0; i < methlist.length; i++) { Method m = methlist; System.out.println("name = " + m.getName()); System.out.println("decl class = " + m.getDeclaringClass()); Class pvec[] = m.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Class evec[] = m.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System.out.println("exc #" + j + " " + evec[j]); System.out.println("return type = " + m.getReturnType()); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。
取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。
输出的结果如下:
name = f1 decl class = class method1 param #0 class java.lang.Object param #1 int exc #0 class java.lang.NullPointerException return type = int-----name = main decl class = class method1 param #0 class [Ljava.lang.String; return type = void
4.获取构造器信息
获取类构造器的用法与上述获取方法的用法类似,如:
import java.lang.reflect.*;public class Constructor1 { public Constructor1() { } protected Constructor1(int i, double d) { } public static void main(String args[]) { try { Class cls = Class.forName("Constructor1"); Constructor ctorlist[] = cls.getDeclaredConstructors(); for (int i = 0; i < ctorlist.length; i++) { Constructor ct = ctorlist; System.out.println("name = " + ct.getName()); System.out.println("decl class = " + ct.getDeclaringClass()); Class pvec[] = ct.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Class evec[] = ct.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System.out.println("exc #" + j + " " + evec[j]); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。
这个程序运行的结果是:
name = Constructor1decl class = class Constructor1param #0 intparam #1 double-----name = Constructor1decl class = class Constructor1-----
5.获取类的字段(域)
找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:
import java.lang.reflect.*; public class Field1 { private double d; public static final int i = 37; String s = "testing"; public static void main(String args[]) { try { Class cls = Class.forName("Field1"); Field fieldlist[] = cls.getDeclaredFields(); for (int i = 0; i < fieldlist.length; i++) { Field fld = fieldlist; System.out.println("name = " + fld.getName()); System.out.println("decl class = " + fld.getDeclaringClass()); System.out.println("type = " + fld.getType()); int mod = fld.getModifiers(); System.out.println("modifiers = " + Modifier.toString(mod)); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是:
name = ddecl class = class Field1type = doublemodifiers = private-----name = idecl class = class Field1type = intmodifiers = public static final-----name = sdecl class = class Field1type = class java.lang.Stringmodifiers = -----
和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。
6.根据方法的名称来执行方法
文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:
import java.lang.reflect.*; public class Method2 { public int add(int a, int b) { return a + b; } public static void main(String args[]) { try { Class cls = Class.forName("Method2"); Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Method meth = cls.getMethod("add", partypes); Method2 methobj = new Method2(); Object arglist[] = new Object[2]; arglist[0] = new Integer(37); arglist[1] = new Integer(47); Object retobj = meth.invoke(methobj, arglist); Integer retval = (Integer) retobj; System.out.println(retval.intValue()); } catch (Throwable e) { System.err.println(e); } } }
假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。
上例中,getMethod用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。
7.创建新的对象
对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:
import java.lang.reflect.*; public class Constructor2 { public Constructor2() { } public Constructor2(int a, int b) { System.out.println("a = " + a + " b = " + b); } public static void main(String args[]) { try { Class cls = Class.forName("Constructor2"); Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Constructor ct = cls.getConstructor(partypes); Object arglist[] = new Object[2]; arglist[0] = new Integer(37); arglist[1] = new Integer(47); Object retobj = ct.newInstance(arglist); } catch (Throwable e) { System.err.println(e); } } }
根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。
8.改变字段(域)的值
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
import java.lang.reflect.*; public class Field2 { public double d; public static void main(String args[]) { try { Class cls = Class.forName("Field2"); Field fld = cls.getField("d"); Field2 f2obj = new Field2(); System.out.println("d = " + f2obj.d); fld.setDouble(f2obj, 12.34); System.out.println("d = " + f2obj.d); } catch (Throwable e) { System.err.println(e); } } }
这个例子中,字段 d 的值被变为了 12.34。
9.使用数组
本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:
import java.lang.reflect.*; public class Array1 { public static void main(String args[]) { try { Class cls = Class.forName("java.lang.String"); Object arr = Array.newInstance(cls, 10); Array.set(arr, 5, "this is a test"); String s = (String) Array.get(arr, 5); System.out.println(s); } catch (Throwable e) { System.err.println(e); } } }
例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。
下面这段代码提供了一个更复杂的例子:
import java.lang.reflect.*; public class Array2 { public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; Object arr = Array.newInstance(Integer.TYPE, dims); Object arrobj = Array.get(arr, 3); Class cls = arrobj.getClass().getComponentType(); System.out.println(cls); arrobj = Array.get(arrobj, 5); Array.setInt(arrobj, 10, 37); int arrcast[][][] = (int[][][]) arr; System.out.println(arrcast[3][5][10]); } }
例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。
欢迎光临 信息发布软件,b2b软件,广告发布软件 (http://postbbs.com/) |
Powered by Discuz! X3.2 |