JAVA反射.docx
《JAVA反射.docx》由会员分享,可在线阅读,更多相关《JAVA反射.docx(37页珍藏版)》请在冰豆网上搜索。
JAVA反射
反射
课程:
检查类
如果你正在编写类的浏览器,你需要一个方式麳获得运行时类的信息。
例如,你想要显示类
的域,方法,构造函数的名字。
或者,你想要显示哪些接口被类实现。
为了获得这个信息你
需要获得Class对象,这个对象反射这个类。
对于每一个类,java运行时环境维护一个不可变的Class对象这个对象包含有关这个类的信
息。
一个Class对象显示或者反射这个类。
使用反射API,你可以调用Class对象的方法,
这个对象可以返回Constructor,Method,Field对象。
你可以使用这些对象麳获得有关定义
在类中的相应的构造函数,方法和域的信息。
Class对象也可以用于接口。
你调用Class方法麳查找相关接口的修饰符,方法,和共有的
常量。
不是所有的Class方法在Class对象反射一个接口的时候都适用。
例如,当Class对象
反射一个接口的时候调用getConstructors是无意义的。
检查接口这一节将会解释哪些Class
的方法你可以使用麳获得关于接口的信息。
获得Class对象
第一件事情,在你查找有关类的任何事情之前,你必须首先获得相应的Class对象。
你可以通过几种方式获得Class对象:
。
如果可以获得一个类的实例,你可以调用Object.getClass。
getClass方法当你想检查一个
不知道类的对象的时候很有用。
以下几行代码可以获得名为mystery的Class对象:
Classc=mystery.getClass();
。
如果你想获得Class对象通过超类这个超类是其它Class对象映像的,调用getSuperclass
方法。
以下的实例,getSuperclass返回Class有关TextComponent类的Class对象,因为
TextComponent是一个TextField的超类:
TextFieldt=newTextField();
Classc=t.getClass();
Classs=c.getSuperclass();
。
如果你想在编译的时候知道类的名字,你可以返回Class对象通过在类的名字后面将
上.class。
在下面的实例中,Button类返回以下Class对象:
Classc=java.awt.Button.class;
。
如果在编译的时候不知道类名,但是在运行时可以知道,你可以使用forName方法。
在
以下的实例中,如果String对象的实例strg设置到java.awt.Button,然后forName返回有关
Button类的Class对象:
Classc=Class.forName(strg);
获得类名
查找Class对象的名字是很容易的。
你所需要做的就是调用getName方法。
在java语言中每一个类都有一个名字。
当你声明一个类后,这个名字跟随在class关键词后
面。
以下的类声明,类名为Point:
publicclassPoint{intx,y;}
在运行时,你可以决定Class对象的名字,通过调用getName方法。
getName方法返回的String
对象是一个类的全路径名。
以下的程序获得一个对象的类名。
第一,它返回相应的Class对象,然后它调用Class对象
的getName方法。
importjava.lang.reflect.*;//这句在这个程序里面没有用到
importjava.awt.*;
反射联络邮箱:
zhiyong.tong@
反射API
反射API表现,或者反射类,接口,和对象在现有的java虚拟机。
你将使用反射API如果
你正在编写开发工具例如调试器,类浏览器,和图形用户界面构建器,使用反射API你可
以:
。
决定对象的类。
。
获得有关类的修改器,域,方法,构建器和超类的信息。
。
查找属于接口的声明方法或者常量。
。
获得直到运行时才明确的类的实例。
。
获得或者设置对象域的值,即使你的域的名字直到运行时才知道。
。
调用对象的方法,即使方法直到运行时才知道。
。
创建一个新的数组,这个数组的长度和组成类型直到运行时才知道,然后修改数组的组成。
首先,要注意的是。
不要在有其它工具更加有效率的情况下使用反射API。
例如,如果你习
惯使用函数指针在其它语言中,你更习惯于使用反射API的Method对象。
请抵御这样的诱
惑!
你的程序将会更加容易调试和维护如果你不使用Method对象。
换言之,你应该定义一
个接口,然后实现这个接口。
其它的课程使用使用术语“成员变量”代替“域”,遮两个术语是相同的。
因为Field类是
反射API的一部分,这个课程使用术语“域”。
这个课程对于反射API使用面向任务的方法。
每一个课程包含一个相关任务的集合,每一
个任务会一步步解释,并有实例程序。
课程目录如下:
。
检查类解释如何决定对象的类,如何获得相关类和接口的信息。
。
操纵对象介绍如何实例化类,获得或者设置域的值,如何调用方法。
使用反射API,你
可以执行这些任务即使你不知道这些类,域,方法的名字,直到运行时。
。
操纵数组描述使用API麳创建和修改数组,这些数组的名字直到运行时才知道。
。
类的总结列出反射API的组成类,提供API文档的链接。
反射联络邮箱:
zhiyong.tong@
classSampleName{
publicstaticvoidmain(String[]args){
Buttonb=newButton();
printName(b);
}
staticvoidprintName(Objecto){
Classc=o.getClass();
Strings=c.getName();
System.out.println(s);
}
}
示例程序打印出如下的语句:
java.awt.Button
发现类修饰符
这一节展示的是你需要查找特定类的修饰符所要调用的方法。
定义一个类需要以下的修饰符:
public,abstract,或者final。
类修饰符在class关键词的前
面。
以下的例子中,类修饰符是public和final:
publicfinalclassCoordinate{intx,inty,intz}
在运行时指定类的修饰符你可以执行以下步骤:
1.调用Class对象的getModifiers方法麳返回修饰符的集合。
2.通过调用isPublic,isAbstract和isFinal方法麳检查修饰符。
以下程序指定String类的修饰符。
importjava.lang.reflect.*;
importjava.awt.*;
classSampleModifier{
publicstaticvoidmain(String[]args){
Strings=newString();
printModifiers(s);
}
publicstaticvoidprintModifiers(Objecto){
Classc=o.getClass();
intm=c.getModifiers();//m为17,是16和1的合,public为1,final为16。
if(Modifier.isPublic(m))
System.out.println("public");
if(Modifier.isAbstract(m))
System.out.println("abstract");
if(Modifier.isFinal(m))
System.out.println("final");
}反射联络邮箱:
zhiyong.tong@
}
示例程序的输出:
public
final
寻找超类
这一节你将要学到如何返回指定类的祖先的所有Class对象。
因为java语言支持继承,一个例如类浏览器的应用程序必须可以指定父类。
为了决定类的
父类,你可以调用getSuperclass方法。
这个方法返回超类的Class对象,或者返回null如果
这个类没有超类。
为了指定所有的父类,可以迭代调用getSuperclass直到返回null为止。
以下这个程序查找Button类的父类的名字。
importjava.lang.reflect.*;
importjava.awt.*;
classSampleSuper{
publicstaticvoidmain(String[]args){
Buttonb=newButton();
printSuperclasses(b);
}
staticvoidprintSuperclasses(Objecto){
Classsubclass=o.getClass();
Classsuperclass=subclass.getSuperclass();
while(superclass!
=null){
StringclassName=superclass.getName();
System.out.println(className);
subclass=superclass;
superclass=subclass.getSuperclass();
}
}
}
示例程序的输出为:
java.awt.Component
java.lang.Object
指定被类实现的接口
如果你想查找一个接口被哪个类实现,请看遮一节。
一个对象的类型不仅在它的类合超类被决定,而且可以被它的接口。
在类声明中,接口在
implements关键词后面被列出。
例如RandomAccessFile类实现DataOutput合DataInput接口:
publicclassRandomAccessFileimplementsDataOutput,DataInput
你调用getInterfaces方法麳决定哪个类实现了接口。
getInterfaces方法返回一个Class对象的
数组。
反射API显示了Class对象。
每一个Class对象在数组中通过getInterfaces返回被这
个类实现的接口。
你可以调用getName方法返回接口的名字。
更多信息,请看检查接口。
以下程序打印RandomAccessFile实现的接口。
importjava.lang.reflect.*;反射联络邮箱:
zhiyong.tong@
importjava.io.*;
classSampleInterface{
publicstaticvoidmain(String[]args){
try{
RandomAccessFiler=newRandomAccessFile("myfile","r");
printInterfaceNames(r);
}catch(IOExceptione){
System.out.println(e);
}
}
staticvoidprintInterfaceNames(Objecto){
Classc=o.getClass();
Class[]theInterfaces=c.getInterfaces();
for(inti=0;iStringinterfaceName=theInterfaces[i].getName();
System.out.println(interfaceName);
}
}
}
打印出以下信息:
java.io.DataOutput
java.io.DataInput
检查接口
这一节你将要学到如果一个Class对象如何现死成一个接口或者一个类。
你将获得一些窍门,
如何获得有关接口的更多信息。
Class对象显示接口与类一样。
如果你不确定一个Class对象到底是接口还是类,调用
isInterface方法。
你调用Class方法麳获得有关接口的信息。
为了查找共有的常量,调用Class对象的getFields
方法。
指定类的域这一节有一个示例包含getFields。
你可以使用getMethods麳获得有关接
口方法的更多信息。
参见获得方法的信息这一节。
查找有关接口的修饰符,调用getModifiers
方法。
参见发现类修饰符的例子。
importjava.lang.reflect.*;
importjava.util.*;
classSampleCheckInterface{
publicstaticvoidmain(String[]args){
Classobserver=Observer.class;
Classobservable=Observable.class;
verifyInterface(observer);
verifyInterface(observable);反射联络邮箱:
zhiyong.tong@
}
staticvoidverifyInterface(Classc){
Stringname=c.getName();
if(c.isInterface()){
System.out.println(name+"isaninterface.");
}else{
System.out.println(name+"isaclass.");
}
}
}
输出如下:
java.util.Observerisaninterface。
Java.util.Observableisaclass。
指定类的域
这一节描述如何发现属于类的域,如何发现这些域的更多信息。
如果你正在编写一个类浏览器的应用程序,你可能想要发现属于一个特定类的域。
你可以指
定类的域通过getFields方法。
getFields方法返回一个Field对象的数组包含每一个可访问的
public域。
一个共有的域可以被任何一个成员访问:
这个类
这个类的超类
实现这个接口的类
这个类实现的接口的接口
这个方法提供Field类允许你返回域的名字,类型合修饰符的结婚。
你可以获得或者设置域
的值,这些在获得域的值合设置域的值中会有描述。
以下的程序打印名字合类型属于GridBagConstraints类。
注意这个程序首先返回Field对象,
然后调用getName合getType方法。
importjava.lang.reflect.*;
importjava.awt.*;
classSampleField{
publicstaticvoidmain(String[]args){
GridBagConstraintsg=newGridBagConstraints();
printFieldNames(g);
}
staticvoidprintFieldNames(Objecto){
Classc=o.getClass();
Field[]publicFields=c.getFields();
for(inti=0;iStringfieldName=publicFields[i].getName();
ClasstypeClass=publicFields[i].getType();反射联络邮箱:
zhiyong.tong@
StringfieldType=typeClass.getName();
System.out.println("Name:
"+fieldName+
",Type:
"+fieldType);
}
}
}
输出如下:
Name:
RELATIVE,Type:
int
Name:
REMAINDER,Type:
int
Name:
NONE,Type:
int
Name:
BOTH,Type:
int
Name:
HORIZONTAL,Type:
int
Name:
VERTICAL,Type:
int
发现类的构造函数
这一节介绍Constructor类,解释如何获得有关类的构造函数的信息。
为了创建一个类的实例,你调用一个特殊的方法,这个方法叫做构造函数。
象方法一样,构
造函数可以被重载。
你可以获得有关类的构造函数的信息,通过调用getConstructors方法,这个方法返回一个
Constructor对象的数组。
你可以使用Constructor类提供的方法麳决定构造函数的名字,修
饰符的结合,参数类型,合抛出异常的集合。
你可以创建一个Constructor对象的实例,通
过Constructor.newInstance犯法。
你将会雪到如何调用Constructor.newInstance方法在操纵对
象这一节。
以下示例程序打印每一个构造函数的参数类型。
程序按以下步骤执行:
1.它返回一个Constructor对象的数组通过调用getConstructors。
2.在Constructor数组的每一个元素,它创建一个Class对象的数组通过调用
getParameterTypes。
Class对象在数组中显示构造函数的参数。
3.程序调用getName麳获得类名。
听起来幷不复杂。
以下是源代码:
importjava.lang.reflect.*;
importjava.awt.*;
classSampleConstructor{
publicstaticvoidmain(String[]args){
Rectangler=newRectangle();
showConstructors(r);
}
staticvoidshowConstructors(Objecto){
Classc=o.getClass();
Constructor[]theConstructors=c.getConstructors();
for(inti=0;iSystem.out.print("(");
Class[]parameterTypes=反射联络邮箱:
zhiyong.tong@
theConstructors[i].getParameterTypes();
for(intk=0;kStringparameterString=parameterTypes[k].getName();
System.out.print(parameterString+"");
}
System.out.println(")");
}
}
}
第一行输出没有参数出现因为特定的Constructor对象显示一个没有参数的构造函数。
在以
下的行。
()
(intint)
(intintintint)
(java.awt.Dimension)
(java.awt.Point)
(java.awt.Pointjava.awt.Dimension)
(java.awt.Rectangle)
获得方法信息
为了发现有关类的方法,你需要返回相应的Method对象。
这一节将展示如何做到这点。
为了发现属于类的共有方法,调用getMethods方法。
返回包含Method对象的数组。
你可以
使用Method对象麳获得方法的名字,返回类型,参数类型,修饰符集合,抛出异常的类型。
所有这些信息在你编写一个类的浏览器或者一个调试器的时候都是很有用的。
通过
Method.invoke,你可以调用方法自身。
想了解如何做到这点,参见调用方法这一节。
以下的示例程序打印名字,返回类型,每一个共有方法的参数类型。
程序执行如下的任务:
1.返回一个Method对象的数组,通过调用getMethods方法。
2.遍历每一个元素:
a)返回方法的名字通过调用getName方法。
b)获得返回类型通过调用getReturnType。
c)创建一个Class对象的数组通过调用getParameterTypes方法。
3.Class对象的数组显示方法的参数。
为了返回每一个参数的类名,程序调用getName方
法。
完成这个任务不需要太多的代码:
importjava.lang.reflect.*;
importjava.awt.*;
classSampleMethod{
publicstaticvoidmain(String[]args){
Polygonp=newPolygon();
showMethods(p);
}
staticvoidshowMethods(Objecto){反射联络邮箱:
zhiyong.tong@
Classc=o.getClass();
Method[]theMethods=c.getMethods();
for(inti=0;iStringmethodString=theMethods[i].getName();
System.out.println("