java的反射技术功能十分强大,整理一些资料!!
(如需转载,请注明出处!)
Lesson: 检测类examing class
1.Retrieving Class Objects
获取一个Class对象(metadata)
a,从对象的实例获取。
Class c = mystery.getClass();//(return Class)
b,从子类的实例获取
TextField t = new TextField();
Class c = t.getClass();
Class s = c.getSuperclass();
c,知道类名,则可以把.class加入到名字之后来获取。
Class c = java.awt.Button.class;
d,如果类名在编译时是未知的,则可以使用Class.forName()方法来获取.
Class c = Class.forName(classString);
2.Getting the Class Name
获取类名称
c.getName();
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleName {
public static void main(String[] args) {
Button b = new Button();
printName(b);
}
static void printName(Object o) {
Class c = o.getClass();
String s = c.getName();
System.out.println(s);
}
}
3.Discovering Class Modifiers
检索修改符
a.通过getModifiers()方法获取一个整型标识值。
b.通过java.reflect.Modifier对象的isPublic, isAbstract, 和 isFinal方法判断此值.
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleModifier {
public static void main(String[] args) {
String s = new String();
printModifiers(s);
}
public static void printModifiers(Object o) {
Class c = o.getClass();
int m = c.getModifiers();
if (Modifier.isPublic(m))
System.out.println("public");
if (Modifier.isAbstract(m))
System.out.println("abstract");
if (Modifier.isFinal(m))
System.out.println("final");
}
}
4.Finding Superclasses
检索父类
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleSuper {
public static void main(String[] args) {
Button b = new Button();
printSuperclasses(b);
}
static void printSuperclasses(Object o) {
Class subclass = o.getClass();
Class superclass = subclass.getSuperclass();
while (superclass != null) {
String className = superclass.getName();
System.out.println(className);
subclass = superclass;
superclass = subclass.getSuperclass();
}
}
}
5.Identifying the Interfaces Implemented by a Class
检索指定类实现的接口
例如:
import java.lang.reflect.*;
import java.io.*;
class SampleInterface {
public static void main(String[] args) {
try {
RandomAccessFile r = new RandomAccessFile("myfile", "r");
printInterfaceNames(r);
} catch (IOException e) {
System.out.println(e);
}
}
static void printInterfaceNames(Object o) {
Class c = o.getClass();
Class[] theInterfaces = c.getInterfaces();
for (int i = 0; i < theInterfaces.length; i++) {
String interfaceName = theInterfaces[i].getName();
System.out.println(interfaceName);
}
}
}
6.Examining Interfaces
判定一个类是不是接口
import java.lang.reflect.*;
import java.util.*;
class SampleCheckInterface {
public static void main(String[] args) {
Class thread = Thread.class;
Class runnable = Runnable.class;
verifyInterface(thread);
verifyInterface(runnable);
}
static void verifyInterface(Class c) {
String name = c.getName();
if (c.isInterface()) {
System.out.println(name + " is an interface.");
} else {
System.out.println(name + " is a class.");
}
}
}
如:c.isInterface()
7.Identifying Class Fields
找出指定类所有的域成员
每个数据成员可以用java.reflect.Field来封闭其名称,类型,修改符的集合。
也可以通过相应的方法获取或设置到该成员的值。
如:
import java.lang.reflect.*;
import java.awt.*;
class SampleField {
public static void main(String[] args) {
GridBagConstraints g = new GridBagConstraints();
printFieldNames(g);
}
static void printFieldNames(Object o) {
Class c = o.getClass();
Field[] publicFields = c.getFields();
for (int i = 0; i < publicFields.length; i++) {
String fieldName = publicFields[i].getName();
Class typeClass = publicFields[i].getType();
String fieldType = typeClass.getName();
System.out.println("Name: " + fieldName +
", Type: " + fieldType);
}
}
}
8.Discovering Class Constructors
检索指定类的构造函数
当创建一个类的实例时,是通过检造方法来作的,这种方法可以被重载。
每一个构造方法可以用类Constructor来描述,,包括名称,修饰符,参数类型(Class[]),和异常列表。
可以通过一个Class的getConstructors方法获取到该类的Constructor数组。
例程:
import java.lang.reflect.*;
import java.awt.*;
class SampleConstructor {
public static void main(String[] args) {
Rectangle r = new Rectangle();
showConstructors(r);
}
static void showConstructors(Object o) {
Class c = o.getClass();
Constructor[] theConstructors = c.getConstructors();
for (int i = 0; i < theConstructors.length; i++) {
System.out.print("( ");
Class[] parameterTypes =
theConstructors[i].getParameterTypes();
for (int k = 0; k < parameterTypes.length; k ++) {
String parameterString = parameterTypes[k].getName();
System.out.print(parameterString + " ");
}
System.out.println(")");
}
}
}
9.Obtaining Method Information
检索方法
可以找到隶属于一个类的所有方法,通过getMethods包含Method数组,进而得到该方法的返回类型,修饰符,方法名称,参数列表
步骤:
a.指定类的Class Object
b.getMethods()获取Method[]对象
c,遍历该数组对象
例程:
import java.lang.reflect.*;
import java.awt.*;
class SampleMethod {
public static void main(String[] args) {
Polygon p = new Polygon();
showMethods(p);
}
static void showMethods(Object o) {
Class c = o.getClass();
Method[] theMethods = c.getMethods();
for (int i = 0; i < theMethods.length; i++) {
String methodString = theMethods[i].getName();
System.out.println("Name: " + methodString);
String returnString =
theMethods[i].getReturnType().getName();
System.out.println(" Return Type: " + returnString);
Class[] parameterTypes = theMethods[i].getParameterTypes();
System.out.print(" Parameter Types:");
for (int k = 0; k < parameterTypes.length; k ++) {
String parameterString = parameterTypes[k].getName();
System.out.print(" " + parameterString);
}
System.out.println();
}
}
}
Lesson:2 处理对象
1.Creating Objects
一般情况下,创建一个对象用以下方法
Rectangle r = new Rectangle();
但如果你正在开发一个development tools,在运行之前或许不知道要生成对象的类。
所以要像下面这样来创建对象:
String className;
// . . . load className from the user interface
Object o = new (className); // WRONG!
但以上是错误的。
正确的方法是使用类的反射特性:
1)Using No-Argument Constructors
例如:
Class classDefinition = Class.forName(className);//指定类的运行期实例
object = classDefinition.newInstance();//调用无参构造函数来生成指定类的实例。
2)Using Constructors that Have Arguments
这个技术要用到如下步骤:
a,创建一个Class对象
b,创建一个Constructor对象,getConstructor(Class[] params)方法,参数是一个与构造方法相适合的Class 数组.
c,在Constructor对象上调用newInstance方法来生成一个对象,参数 是一个object数组与这个构造方法相配备。
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleInstance {
public static void main(String[] args) {
Rectangle rectangle;
Class rectangleDefinition;
Class[] intArgsClass = new Class[] {int.class, int.class};
Integer height = new Integer(12);
Integer width = new Integer(34);
Object[] intArgs = new Object[] {height, width};
Constructor intArgsConstructor;
try {
//1.
rectangleDefinition = Class.forName("java.awt.Rectangle");
//2.
intArgsConstructor =
rectangleDefinition.getConstructor(intArgsClass);//找到指定的构造方法
//3.
rectangle =
(Rectangle) createObject(intArgsConstructor, intArgs);//构造方法描述对象,object[]
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (NoSuchMethodException e) {
System.out.println(e);
}
}
public static Object createObject(Constructor constructor,
Object[] arguments) {
System.out.println ("Constructor: " + constructor.toString());
Object object = null;
try {
object = constructor.newInstance(arguments);
System.out.println ("Object: " + object.toString());
return object;
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
return object;
}
}
2。Getting Field Values
If you are writing a development tool such as a debugger, you must be able to obtain field values. This is a three-step process:
如果要作一个开发工具像debugger之类的,你必须能发现filed values,以下是三个步骤:
a.创建一个Class对象
b.通过getField 创建一个Field对象
c.调用Field.getXXX(Object)方法(XXX是Int,Float等,如果是对象就省略;Object是指实
例).
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleGet {
public static void main(String[] args) {
Rectangle r = new Rectangle(100, 325);
printHeight(r);
}
static void printHeight(Rectangle r) {
Field heightField;
Integer heightValue;
Class c = r.getClass();
try {
heightField = c.getField("height");
heightValue = (Integer) heightField.get(r);
System.out.println("Height: " + heightValue.toString());
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
}
3。Setting Field Values
a.创建一个Class对象
b.通过getField 创建一个Field对象
c.调用Field.set(Object,withparam)方法(XXX是Int,Float等,如果是对象就省略;Object是指实例,withparam指和这个字段相区配的字段。
import java.lang.reflect.*;
import java.awt.*;
class SampleSet {
public static void main(String[] args) {
Rectangle r = new Rectangle(100, 20);
System.out.println("original: " + r.toString());
modifyWidth(r, new Integer(300));
System.out.println("modified: " + r.toString());
}
static void modifyWidth(Rectangle r, Integer widthParam ) {
Field widthField;
Integer widthValue;
Class c = r.getClass();
try {
widthField = c.getField("width");
widthField.set(r, widthParam);
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
}
4。调用指定的方法
a.创建一个Class对象
b.创建一个方法对象method,getMethod(String methodName,Class[])方法
c.调方法对象,method.invoke(object,Object[]),两个参数,第一个是指调用方法所属于的对象,第二个是传递的值对象列表。
The sample program that follows shows you how to invoke a method dynamically. The program retrieves the Method object for the String.concat method and then uses invoke to concatenate two String objects.
//
import java.lang.reflect.*;
class SampleInvoke {
public static void main(String[] args) {
String firstWord = "Hello "; //指定类的实例
String secondWord = "everybody.";//变元
String bothWords = append(firstWord, secondWord);
System.out.println(bothWords);
}
public static String append(String firstWord, String secondWord) {
String result = null;
Class c = String.class;
Class[] parameterTypes = new Class[] {String.class};
Method concatMethod;
Object[] arguments = new Object[] {secondWord};
try {
concatMethod = c.getMethod("concat", parameterTypes);//获取到方法对象
result = (String) concatMethod.invoke(firstWord, arguments);//调用
} catch (NoSuchMethodException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
return result;
}
}
特此声明这些资料的原始内容来自www.java.sun.com,本人只是对其内容在个人的理解的基础上,进行翻译和整理。
一.概述
Reflection API可以使JAVA代码动态的查询和操作正在运行的JAVA类或者接口。Reflection 包含许多的类,例如Method类,该类可以在java.lang.reflect包中找到。
使用Reflection 中的类需要三个步骤:
1.获取一个要操作的类的对象,该对象属于java.lang.object包,该对象代表一个正在运行的一个类或接口。下面的三个方法是常用的获取类对象的方法:
(1) Class c=Class.forname(“java.lang.String”);
使用.forname方法加载一个类,这里是字符串类,从而获得一个与该类对应的类对象。
(2) Class c=int.class;
(3) Class c=Integer.TYPE;
2.获取要操纵的类对象的已经声明的方法
获取类对象的方法的最简单和常用的方法是getDeclareMethods()方法。该方法返回类对象中声明过的所有方法的一个方法数组(Method[])。还有其他的方法,在后面会有所介绍。
3.利用Reflection API操作类。
二.Java.lang.reflect包介绍
java.lang.reflect包中包含有两个接口,八个类。
InvocationHandler接口:
Member接口:该接口可以获取有关类成员(域或者方法)后者构造函数的信息。
AccessibleObject类:该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。
Array类:该类提供动态地生成和访问JAVA数组的方法。
Constructor类:提供一个类的构造函数的信息以及访问类的构造函数的接口。
Field类:提供一个类的域的信息以及访问类的域的接口。
Method类:提供一个类的方法的信息以及访问类的方法的接口。
Modifier类:
Proxy类:提供动态地生成代理类和类实例的静态方法。
ReflectionPermission类:
三.示例与说明
3.1 查找类中声明过的所有方法
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[i];
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); }
}
}
代码说明:
Class cls = Class.forName("method1");获取一个method1类的类对象cls。
Method methlist[] = cls.getDeclaredMethods();返回一个类声明的所有方法的方法数组。
m.getDeclaringClass();返回声明该方法的类的实例。返回值为一个class。
m.getName():返回该方法的名字,返回值为字符串类型。
Class pvec[] = m.getParameterTypes():返回该方法的参数的类型的一个数组。注意参数的返回顺序是与方法声明时的顺序是相同的。
Class evec[] = m.getExceptionTypes():获取该方法抛出的例外的一个类型数组。
m.getReturnType():返回该方法的返回值的类型。返回值是一个class。
除了上述的Method类的方法外,还有别的方法。其中比较重要的有:
Object invoke(Object obj,Object[] args)方法:对该方法进行实际的调用并执行。其中的两个参数的含义分别是调用该方法的一个类实例对象,和调用该方法的参数对象数组。具体如何应用请参看3.4节。
3.2 获取构造函数信息
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[i];
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); }
}
}
Constructor ctorlist[] = cls.getDeclaredConstructors():获取该实例对象声明的所有的构造函数数组。
ct.getName():获取该构造函数的名称,返回值是一个字符串类型的变量。
ct.getDeclaringClass():返回声明该构造函数的类。返回值是一个class。
Class pvec[] = ct.getParameterTypes():返回该构造函数的参数的一个类型数组。返回的是一个class类型的数组。
Class evec[] = ct.getExceptionTypes():返回一个该构造函数的抛出的例外的一个类型数组。
除了上述的方法外,对于Constructor类还有一个很重要的方法:
Object newInstance(Object iniargs[]):实际调用该构造函数并且生成一个实例对象。具体的应用参看3.5节。
3.3 获取类中域的信息
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[i];
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); }
}
}
3.4 通过方法名调用方法
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); }
}
}
我们会仔细地介绍方法调用的实现。
首先,声明了一个类method2,该类有一个方法public int add(int a, int b)。请注意该方法的方法名’add’、两个形式参数的数据类型int以及返回值类型int。因为,这些信息对动态地调用一个类的方法是非常重要的。
接下来在主调函数中实现的功能如下:
1.Class cls = Class.forName("method2"):获取类实例对象cls。
2.Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
声明一个类数组,用来保存两个参数的数据类型。
3.Method meth = cls.getMethod("add", partypes);注意getMethod方法,该方法将返回一个匹配的方法。匹配的条件,有两部分来限定。一个是方法名,一个是方法的参数类型数组。(因为JAVA中允许方法的重载,所以必须说明参数的数据类型)参数类型数组中的各个参数类型的顺序必须与方法声明时的顺序相同。
4.method2 methobj = new method2():声明一个类method2的实例变量。
5.Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
声明一个对象数组,来存储两个参数实例。
6.Object retobj = meth.invoke(methobj, arglist):实际调用add函数。注意方法invoke()的两个参数,methobj是调用方法(或者是声明方法)的类的一个实例,arglist确实被调用方法(这里是add方法)的,参数实例数组。返回值仍然是一个对象的实例retobj。
7.Integer retval = (Integer)retobj;
System.out.println(retval.intValue());将返回的对象实例,进行类型转换,并输出。
3.5 生成一个新的实例
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); }
}
}
这个例子说明了Constructor类的newInstancce()方法的使用。其具体的过程与3.4节中使用invoke()方法类似,不再多说了。