蒙在股里 发表于 2015-1-18 11:41:22

JAVA编程:Java中的类反射机制

手机用到的是用j2me所编出来的小程序。1、反射的观点:
反射的观点是由Smith在1982年初次提出的,次要是指程序能够会见、检测和修正它自己形态或举动的一种才能。这一观点的提出很快激发了盘算机迷信范畴关于使用反射性的研讨。它起首被程序言语的计划范畴所接纳,并在Lisp和面向对象方面获得了成就。个中LEAD/LEAD++、OpenC++、MetaXa和OpenJava等就是基于反射机制的言语。比来,反射机制也被使用到了视窗体系、操纵体系和文件体系中。

反射自己并非一个新观点,它大概会使我们遐想到光学中的反射观点,只管盘算机迷信付与了反射观点新的寄义,可是,从征象下去说,它们的确有某些相通的地方,这些有助于我们的了解。在盘算机迷信范畴,反射是指一类使用,它们可以自形貌和自把持。也就是说,这类使用经由过程接纳某种机制来完成对本人举动的形貌(self-representation)和监测(examination),并能依据本身举动的形态和了局,调剂或修正使用所形貌举动的形态和相干的语义。能够看出,统一般的反射观点比拟,盘算机迷信范畴的反射不但单指反射自己,还包含对反射了局所接纳的措施。一切接纳反射机制的体系(即反射体系)都但愿使体系的完成更开放。能够说,完成了反射机制的体系都具有开放性,但具有开放性的体系其实不必定接纳了反射机制,开放性是反射体系的需要前提。一样平常来讲,反射体系除满意开放性前提外还必需满意缘故原由毗连(Causally-connected)。所谓缘故原由毗连是指对反射体系自形貌的改动可以当即反应到体系底层的实践形态和举动上的情形,反之亦然。开放性和缘故原由毗连是反射体系的两年夜基础要素。13700863760

Java中,反射是一种壮大的工具。它使您可以创立天真的代码,这些代码能够在运转古装配,无需在组件之间举行源代表链接。反射同意我们在编写与实行时,使我们的程序代码可以接进装载到JVM中的类的外部信息,而不是源代码当选定的类合作的代码。这使反射成为构建天真的使用的次要工具。但需注重的是:假如利用不妥,反射的本钱很高。

2、Java中的类反射:
Reflection是Java程序开辟言语的特性之一,它同意运转中的Java程序对本身举行反省,大概说“自审”,并能间接操纵程序的外部属性。Java的这一才能在实践使用中大概用得不是良多,可是在别的的程序计划言语中基本就不存在这一特征。比方,Pascal、C大概C++中就没有举措在程序中取得函数界说相干的信息。

1.检测类:

1.1reflection的事情机制

思索上面这个复杂的例子,让我们看看reflection是怎样事情的。

importjava.lang.reflect.*;
publicclassDumpMethods{
publicstaticvoidmain(Stringargs[]){
try{
Classc=Class.forName(args);
Methodm[]=c.getDeclaredMethods();
for(inti=0;i<m.length;i++)
System.out.println(m.toString());
}catch(Throwablee){
System.err.println(e);
}
}
}

按以下语句实行:

javaDumpMethodsjava.util.Stack

它的了局输入为:

publicjava.lang.Objectjava.util.Stack.push(java.lang.Object)

publicsynchronizedjava.lang.Objectjava.util.Stack.pop()

publicsynchronizedjava.lang.Objectjava.util.Stack.peek()

publicbooleanjava.util.Stack.empty()

publicsynchronizedintjava.util.Stack.search(java.lang.Object)

如许就列出了java.util.Stack类的各办法名和它们的限定符和前往范例。

这个程序利用Class.forName载进指定的类,然后挪用getDeclaredMethods来猎取这个类中界说了的办法列表。java.lang.reflect.Methods是用来形貌某个类中单个办法的一个类。

1.2Java类反射中的次要办法

关于以下三类组件中的任何一类来讲--机关函数、字段和办法--java.lang.Class供应四种自力的反射挪用,以分歧的体例来取得信息。挪用都遵守一种尺度格局。以下是用于查找机关函数的一组反射挪用:

lConstructorgetConstructor(Class[]params)--取得利用特别的参数范例的大众机关函数,

lConstructor[]getConstructors()--取得类的一切大众机关函数

lConstructorgetDeclaredConstructor(Class[]params)--取得利用特定参数范例的机关函数(与接进级别有关)

lConstructor[]getDeclaredConstructors()--取得类的一切机关函数(与接进级别有关)

取得字段信息的Class反射挪用分歧于那些用于接进机关函数的挪用,在参数范例数组中利用了字段名:

lFieldgetField(Stringname)--取得定名的大众字段

lField[]getFields()--取得类的一切大众字段

lFieldgetDeclaredField(Stringname)--取得类声明的定名的字段

lField[]getDeclaredFields()--取得类声明的一切字段

用于取得办法信息函数:

lMethodgetMethod(Stringname,Class[]params)--利用特定的参数范例,取得定名的大众办法

lMethod[]getMethods()--取得类的一切大众办法

lMethodgetDeclaredMethod(Stringname,Class[]params)--利用特写的参数范例,取得类声明的定名的办法

lMethod[]getDeclaredMethods()--取得类声明的一切办法



1.3入手下手利用Reflection:

用于reflection的类,如Method,能够在java.lang.relfect包中找到。利用这些类的时分必需要遵守三个步骤:第一步是取得你想操纵的类的java.lang.Class对象。在运转中的Java程序中,用java.lang.Class类来形貌类和接口等。

上面就是取得一个Class对象的办法之一:

Classc=Class.forName("java.lang.String");

这条语句失掉一个String类的类对象。另有另外一种办法,以下面的语句:

Classc=int.class;

大概

Classc=Integer.TYPE;

它们可取得基础范例的类信息。个中后一种办法中会见的是基础范例的封装类(如Integer)中事后界说好的TYPE字段。

第二步是挪用诸如getDeclaredMethods的办法,以获得该类中界说的一切办法的列表。

一旦获得这个信息,就能够举行第三步了――利用reflectionAPI来操纵这些信息,以下面这段代码:

Classc=Class.forName("java.lang.String");

Methodm[]=c.getDeclaredMethods();

System.out.println(m.toString());

它将以文本体例打印出String中界说的第一个办法的原型。

2.处置对象:

假如要作一个开辟工具像debugger之类的,你必需能发明filedvalues,以下是三个步骤:

a.创立一个Class对象
b.经由过程getField创立一个Field对象
c.挪用Field.getXXX(Object)办法(XXX是Int,Float等,假如是对象就省略;Object是指实例).

比方:
importjava.lang.reflect.*;
importjava.awt.*;

classSampleGet{

publicstaticvoidmain(String[]args){
Rectangler=newRectangle(100,325);
printHeight(r);

}

staticvoidprintHeight(Rectangler){
FieldheightField;
IntegerheightValue;
Classc=r.getClass();
try{
heightField=c.getField("height");
heightValue=(Integer)heightField.get(r);
System.out.println("Height:"+heightValue.toString());
}catch(NoSuchFieldExceptione){
System.out.println(e);
}catch(SecurityExceptione){
System.out.println(e);
}catch(IllegalAccessExceptione){
System.out.println(e);
}
}
}



3、平安性和反射:
在处置反射时平安性是一个较庞大的成绩。反射常常由框架型代码利用,因为这一点,我们大概但愿框架可以周全接进代码,无需思索惯例的接进限定。可是,在别的情形下,不受把持的接进会带来严峻的平安性风险,比方今世码在不值得信托的代码共享的情况中运转时。

因为这些相互冲突的需求,Java编程言语界说一种多级别办法来处置反射的平安性。基础形式是对反射实行与使用于源代码接进不异的限定:

n从恣意地位到类大众组件的接进

n类本身内部无任何到公有组件的接进

n受回护和打包(缺省接进)组件的无限接进

不外最少有些时分,环绕这些限定另有一种复杂的办法。我们能够在我们所写的类中,扩大一个一般的基础类java.lang.reflect.AccessibleObject类。这个类界说了一种setAccessible办法,使我们可以启动或封闭对这些类中个中一个类的实例的接进检测。独一的成绩在于假如利用了平安性办理器,它将检测正在封闭接进检测的代码是不是允许了如许做。假如未允许,平安性办理器抛出一个破例。

上面是一段程序,在TwoString类的一个实例上利用反射来显现平安性正在运转:

publicclassReflectSecurity{

publicstaticvoidmain(String[]args){

try{

TwoStringts=newTwoString("a","b");

Fieldfield=clas.getDeclaredField("m_s1");

//field.setAccessible(true);

System.out.println("Retrievedvalueis"+

field.get(inst));

}catch(Exceptionex){

ex.printStackTrace(System.out);

}

}

}

假如我们编译这一程序时,不利用任何特定参数间接从命令交运行,它将在field.get(inst)挪用中抛出一个IllegalAccessException非常。假如我们不正文field.setAccessible(true)代码行,那末从头编译偏重新运转该代码,它将编译乐成。最初,假如我们在命令行增加了JVM参数-Djava.security.manager以完成平安性办理器,它仍旧将不克不及经由过程编译,除非我们界说了ReflectSecurity类的允许权限。

4、反射功能:
反射是一种壮大的工具,但也存在一些不敷。一个次要的弱点是对功能有影响。利用反射基础上是一种注释操纵,我们能够告知JVM,我们但愿做甚么而且它满意我们的请求。这类操纵老是慢于只间接实行不异的操纵。

上面的程序是字段接进功能测试的一个例子,包含基础的测试办法。每种办法测试字段接进的一种情势--accessSame与统一对象的成员字段合作,accessOther利用可间接接进的另外一对象的字段,accessReflection利用可经由过程反射接进的另外一对象的字段。在每种情形下,办法实行不异的盘算--轮回中复杂的加/乘按次。

程序以下:

publicintaccessSame(intloops){

m_value=0;

for(intindex=0;index<loops;index++){

m_value=(m_value+ADDITIVE_VALUE)*

MULTIPLIER_VALUE;

}

returnm_value;

}



publicintaccessReference(intloops){

TimingClasstiming=newTimingClass();

for(intindex=0;index<loops;index++){

timing.m_value=(timing.m_value+ADDITIVE_VALUE)*

MULTIPLIER_VALUE;

}

returntiming.m_value;

}



publicintaccessReflection(intloops)throwsException{

TimingClasstiming=newTimingClass();

try{

Fieldfield=TimingClass.class.

getDeclaredField("m_value");

for(intindex=0;index<loops;index++){

intvalue=(field.getInt(timing)+

ADDITIVE_VALUE)*MULTIPLIER_VALUE;

field.setInt(timing,value);

}

returntiming.m_value;

}catch(Exceptionex){

System.out.println("Errorusingreflection");

throwex;

}

}

在下面的例子中,测试程序反复挪用每种办法,利用一个年夜轮回数,从而均匀屡次挪用的工夫权衡了局。均匀值中不包含每种办法第一次挪用的工夫,因而初始化工夫不是了局中的一个要素。上面的图分明的向我们展现了每种办法字段接进的工夫:

:字段接进工夫:

我们能够看出:在前两副图中(SunJVM),利用反射的实行工夫凌驾利用间接接进的1000倍以上。经由过程对照,IBMJVM大概稍好一些,但反射办法仍然必要比别的办法长700倍以上的工夫。任何JVM上别的两种办法之间工夫方面无任何明显差别,但IBMJVM几近比SunJVM快一倍。最有大概的是这类差别反应了SunHotSpotJVM的专业优化,它在复杂基准方面体现得很糟。反射功能是Sun开辟1.4JVM时存眷的一个方面,它在反射办法挪用了局中显现。在这类操纵的功能方面,Sun1.4.1JVM显现了比1.3.1版本很年夜的改善。

假如为为创立利用反射的对象编写了相似的计时测试程序,我们会发明这类情形下的差别不象字段和办法挪用情形下那末明显。利用newInstance()挪用创立一个复杂的java.lang.Object实例耗用的工夫约莫是在Sun1.3.1JVM上利用newObject()的12倍,是在IBM1.4.0JVM的四倍,只是Sun1.4.1JVM上的两部。利用Array.newInstance(type,size)创立一个数组耗用的工夫是任何测试的JVM上利用newtype的两倍,跟着数组巨细的增添,差别慢慢减少。

停止语:
Java言语反射供应一种静态链接程序组件的多功效办法。它同意程序创立和把持任何类的对象(依据平安性限定),无需提早硬编码方针类。这些特征使得反射出格合用于创立以十分一般的体例与对象合作的库。比方,反射常常在延续存储对象为数据库、XML或别的内部格局的框架中利用。Javareflection十分有效,它使类和数据布局能按称号静态检索相干信息,并同意在运转着的程序中操纵这些信息。Java的这一特征十分壮大,而且是别的一些经常使用言语,如C、C++、Fortran大概Pascal等都不具有的。

但反射有两个弱点。第一个是功能成绩。用于字段和办法接进时反射要远慢于间接代码。功能成绩的水平取决于程序中是怎样利用反射的。假如它作为程序运转中绝对很少触及的部分,迟缓的功能将不会是一个成绩。即便测试中最坏情形下的计时图显现的反射操纵只耗用几微秒。仅反射在功能关头的使用的中心逻辑中利用时功能成绩才变得相当主要。

很多使用中更严峻的一个弱点是利用反射会含混程序外部实践要产生的事变。程序职员但愿在源代码中看到程序的逻辑,反射等绕过了源代码的手艺会带来保护成绩。反射代码比响应的间接代码更庞大,正如功能对照的代码实例中看到的一样。办理这些成绩的最好计划是守旧地利用反射――仅在它能够真正增添天真性的中央――纪录其在方针类中的利用。





使用反射完成类的静态加载




Bromon原创请尊敬版权

比来在成都写一个挪动增值项目,俺卖力背景server端。功效很复杂,手机用户经由过程GPRS翻开Socket与服务器毗连,我则依据用户传过去的数据做出呼应。做过相似项目标兄弟必定都晓得,起首必要界说一个相似于MSNP的通信协定,不外明天的话题是怎样把这个体系计划得具有高度的扩大性。因为这个项目自己没有举行过较为完美的客户相同和需求剖析,以是今后一定会有良多功效上的扩大,通信协定一定会愈来愈复杂,而我作为一个不那末勤劳的人,固然不想今后再往修正写好的程序,以是这个项目是理论面向对象计划的好时机。

起首界说一个接口来断绝类:

packageorg.bromon.reflect;

publicinterfaceOperator

{

publicjava.util.Listact(java.util.Listparams)

}

依据计划形式的道理,我们能够为分歧的功效编写分歧的类,每一个类都承继Operator接口,客户端只必要针对Operator接口编程就能够制止良多贫苦。好比这个类:

packageorg.bromon.reflect.*;

publicclassSuccessimplementsOperator

{

publicjava.util.Listact(java.util.Listparams)

{

Listresult=newArrayList();

result.add(newString(“操纵乐成”));

returnresult;

}

}

我们还能够写其他良多类,可是有个成绩,接口是没法实例化的,我们必需手动把持详细实例化哪一个类,这很不爽,假如可以向使用程序传送一个参数,让本人往选择实例化一个类,实行它的act办法,那我们的事情就轻松多了。

很侥幸,我利用的是Java,只要Java才供应如许的反射机制,大概说内省机制,能够完成我们的在理请求。编写一个设置文件emp.properties:

#乐成呼应

1000=Success

#向客户发送一般文本动静

2000=Load

#客户向服务器发送一般文本动静

3000=Store

文件中的键名是客户将发给我的动静头,客户发送1000给我,那末我就实行Success类的act办法,相似的假如发送2000给我,那就实行Load类的act办法,如许一来体系就完整切合开闭准绳了,假如要增加新的功效,完整不必要修正已有代码,只必要在设置文件中增加对应划定规矩,然后编写新的类,完成act办法就ok,即便我弃这个项目而往,它未来也能够很好的扩大。如许的体系具有了十分优秀的扩大性和可拔出性。

上面这个例子表现了静态加载的功效,程序在实行过程当中才晓得应当实例化哪一个类:

packageorg.bromon.reflect.*;

importjava.lang.reflect.*;

publicclassTestReflect

{

//加载设置文件,查询动静头对应的类名

privateStringloadProtocal(Stringheader)

{

Stringresult=null;

try

{

Propertiesprop=newProperties();

FileInputStreamfis=newFileInputStream("emp.properties");

prop.load(fis);

result=prop.getProperty(header);

fis.close();

}catch(Exceptione)

{

System.out.println(e);

}

returnresult;

}

//针抵消息作出呼应,使用反射导进对应的类

publicStringresponse(Stringheader,Stringcontent)

{

Stringresult=null;

Strings=null;

try

{

/*

*导进属性文件emp.properties,查询header所对应的类的名字

*经由过程反射机制静态加载婚配的类,一切的类都被Operator接口断绝

*能够经由过程修正属性文件、增加新的类(承继MsgOperator接口)来扩大协定

*/

s="org.bromon.reflect."+this.loadProtocal(header);

//加载类

Classc=Class.forName(s);

//创立类的事例

Operatormo=(Operator)c.newInstance();

//机关参数列表

Classparams[]=newClass;

params=Class.forName("java.util.List");

//查询act办法

Methodm=c.getMethod("act",params);

Objectargs[]=newObject;

args=content;

//挪用办法而且取得前往

ObjectreturnObject=m.invoke(mo,args);

}catch(Exceptione)

{

System.out.println("Handler-response:"+e);

}

returnresult;

}

publicstaticvoidmain(Stringargs[])

{

TestReflecttr=newTestReflect();

tr.response(args,”动静内容”);

}

}

测试一下:javaTestReflect1000

这个程序是针对Operator编程的,以是无需做任何修正,间接供应Load和Store类,就能够撑持2000、3000做参数的挪用。

有了如许的内省机制,能够把接口的感化发扬到极至,计划形式也更能表现出能力,而不单单供我们饭后闲谈。




进而能拉拢大多数程序员用windows产品。并且从ASP.NETAJAX可以跨平台这一点上,间接证明了我们的推断,至少证明了微软做过这方面的研究。所以如果哪一天突然听说了.net可以跨平台了,那么请不要吃惊,如果这一天真的到来,java就到了真正和.net决战的时刻。因为不到万不得以的时候微软是不会推出跨平台的.net的,如果跨平台的.net还不足以对抗java的话,那么微软还剩的手段就是开源了,呵呵。

分手快乐 发表于 2015-1-21 12:52:27

有时间再研究一下MVC结构(把Model-View-Control分离开的设计思想)

若天明 发表于 2015-1-26 05:48:13

另外编写和运行Java程序需要JDK(包括JRE),在sun的官方网站上有下载,thinking in java第三版用的JDK版本是1.4,现在流行的版本1.5(sun称作J2SE 5.0,汗),不过听说Bruce的TIJ第四版国外已经出来了,是专门为J2SE 5.0而写的。

若相依 发表于 2015-1-31 19:03:22

http://www.jdon.com/去下载,或到同济技术论坛的服务器ftp://nro.shtdu.edu.cn去下,安装上有什么问题,可以到论坛上去提问。

小魔女 发表于 2015-2-6 21:07:03

还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。

活着的死人 发表于 2015-2-11 00:29:31

是一种语言,用以产生「小应用程序(Applet(s))

再见西城 发表于 2015-3-1 18:50:00

当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢?

深爱那片海 发表于 2015-3-6 18:34:06

是一种使网页(Web Page)由静态(Static)转变为动态(Dynamic)的语言

飘飘悠悠 发表于 2015-3-8 05:06:40

所以现在应用最广泛又最好学的就是J2EE了。 J2EE又包括许多组件,如Jsp,Servlet,JavaBean,EJB,JDBC,JavaMail等。要学习起来可不是一两天的事。那么又该如何学习J2EE呢?当然Java语法得先看一看的,I/O包,Util包,Lang包你都熟悉了吗?然后再从JSP学起。

兰色精灵 发表于 2015-3-15 15:24:02

当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢?

飘灵儿 发表于 2015-3-17 09:09:57

你可以去承接一些项目做了,一开始可能有些困难,可是你有技术积累,又考虑周全,接下项目来可以迅速作完,相信大家以后都会来找你的,所以Money就哗啦啦的。。。。。。

愤怒的大鸟 发表于 2015-3-22 21:09:34

Jive的资料在很多网站上都有,大家可以找来研究一下。相信你读完代码后,会有脱胎换骨的感觉。遗憾的是Jive从2.5以后就不再无条件的开放源代码,同时有licence限制。不过幸好还有中国一流的Java程序员关注它,外国人不开源了,中国人就不能开源吗?这里向大家推荐一个汉化的Jive版本—J道。Jive(J道版)是由中国Java界大名 鼎鼎的banq在Jive 2.1版本基础上改编而成, 全中文,增加了一些实用功能,如贴图,用户头像和用户资料查询等,而且有一个开发团队在不断升级。你可以访问banq的网站

莫相离 发表于 2015-4-11 12:57:21

http://www.jdon.com/去下载,或到同济技术论坛的服务器ftp://nro.shtdu.edu.cn去下,安装上有什么问题,可以到论坛上去提问。

蒙在股里 发表于 2015-4-16 05:10:22

当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢?

简单生活 发表于 2015-4-20 16:03:28

http://www.jdon.com/去下载,或到同济技术论坛的服务器ftp://nro.shtdu.edu.cn去下,安装上有什么问题,可以到论坛上去提问。

冷月葬花魂 发表于 2015-4-27 11:40:43

在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。

爱飞 发表于 2015-4-28 03:11:01

我大二,Java也只学了一年,觉得还是看thinking in java好,有能力的话看英文原版(中文版翻的不怎么好),还能提高英文文档阅读能力。

海妖 发表于 2015-6-18 09:48:02

是一种简化的C++语言 是一种安全的语言,具有阻绝计算机病毒传输的功能

小妖女 发表于 2015-7-1 01:27:14

是一种语言,用以产生「小应用程序(Applet(s))
页: [1]
查看完整版本: JAVA编程:Java中的类反射机制