一、java类反射中所必须的类Field、Constructor、Method、Class、Object
Field类:提供有关类或接口的属性的信息。发射的字段可能是类属性或实例属性,可以看成一个封装了反射类的属性的类
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限
Method类:用类封装反射类方法的一个类
Class类:表示正在运行的java应用程序中的类和接口
Object类:每个类都使用Object作为超类。所有对象包括数组都实现这个类的方法。
二、新建一个A类用来表示反射类继承了Object类,有一个接口是ActionListener,两个属性int和Integer,两个构造方法和两个方法
A类java代码
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class A extends Object implements ActionListener {
private int a = 3;
public Integer b = new Integer(4);
public A() {
}
public A(int id, String name) {
}
public int abc(int id, String name) {
return 0;
}
public void actionPerformed(ActionEvent e) {
}
}
B类java代码
import java.lang.reflect.Field;
public class B {
public static void main(String[] args) {
// TODO Auto-generated method stub
A r = new A();
Class temp = r.getClass();
try {
System.out.println("反射类中所有公有的属性");
Field[] fb = temp.getFields();
for (int i = 0; i < fb.length; i++) {
Class cl = fb[i].getType();
System.out.println("fb:" + cl);
System.out.println("fb:" + fb[i].get(r));
}
System.out.println("反射类中所有的属性");
Field[] fa = temp.getDeclaredFields();
for (int i = 0; i < fa.length; i++) {
Class cl = fa[i].getType();
System.out.println("fb:" + cl);
}
System.out.println("反射类中似有的属性");
Field aField = temp.getDeclaredField("a");
aField.setAccessible(true);
aField.set(r, 6);
Integer aValue = (Integer) aField.get(r);
System.out.println("a=" + aValue);
} catch (Exception e) {
// TODO: handle exception
}
}
}
这里用了两类方法:getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来获取反射类中指定的属性的方法
这里还用到了Field类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。
三、如何获取反射类中的构造方法
SampleConstructor.java代码
import java.lang.reflect.Constructor;
public class SampleConstructors {
public static void main(String[] args) {
A r = new A();
Class temp = r.getClass();
// 获取类的名字
String stringName = temp.getName();
Constructor[] theConstructor = temp.getConstructors();
for (int i = 0; i < theConstructor.length; i++) {
Class[] paramClass = theConstructor[i].getParameterTypes();
System.out.print("A(");
for (int j = 0; j < paramClass.length; j++) {
System.out.print(paramClass[j].getName() + " ");
}
System.out.println(")");
}
}
}
用getConstructors()方法获取了反射类的构造方法的集合,并用Constructor类的getParameterTypes()获取该构造方法的参数。
四、如何获取反射类的父类和接口
SampleInterface.java代码
public class SampleInterface {
public static void main(String[] args) {
// TODO Auto-generated method stub
A r = new A();
Class temp = r.getClass();
Class[] theInterfaces = temp.getInterfaces();
for (int i = 0; i < theInterfaces.length; i++) {
// 获取接口的名字
System.out.println(theInterfaces[i].getName());
}
// 获取父类的名字
Class theSuperClass = temp.getSuperclass();
System.out.println(theSuperClass.getName());
}
}
用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回的是数组。用getSuperClass()方法来获取反射类的父类,由于一个类只能继承一个类,所以它返回一个Class对象。
五、如何获取反射类的方法
SampleMethod.java代码
import java.lang.reflect.Method;
public class SampleMethod {
public static void main(String[] args) {
A r = new A();
Class temp = r.getClass();
String className = temp.getName();
Method[] methods = temp.getMethods();
for (int i = 0; i < methods.length; i++) {
// 输出方法的返回类型
System.out.print(methods[i].getReturnType().getName());
// 输出方法名
System.out.print(" " + methods[i].getName() + "(");
// 获取方法的参数
Class[] paramTypes = methods[i].getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
System.out.print(paramTypes[j].getName());
if (paramTypes.length > j + 1) {
System.out.print(",");
}
}
System.out.println(")");
}
}
}
获取了反射类的所有方法,包括继承自它父类的方法。然后获取方法的返回值、方法名、参数列表。
六、下面是一个完整的小例子
LoadMethod.java
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethod {
/**
* 运行时加载指定的类
*/
public Object Load(String cName, String methodName, String[] type,
String[] param) {
Object retobj = null;
try {
// 加载指定的java类
Class cls = Class.forName(cName);
// 获取指定对象的实例
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
// 构建方法参数的数据类型
Class paramTypes[] = this.getMethodClass(type);
// 在指定类中获取指定的方法
Method meth = cls.getMethod(methodName, paramTypes);
// 构建方法的参数值
Object arglist[] = this.getMethodObject(type, param);
// 调用指定的方法并获取返回值为Object类型
retobj = meth.invoke(obj, arglist);
} catch (Exception e) {
System.err.println(e);
}
return retobj;
}
/**
* 获取参数类型Class[]的方法
*/
public Class[] getMethodClass(String[] type) {
Class[] cs = new Class[type.length];
for (int i = 0; i < cs.length; i++) {
if (!type[i].trim().equals("") || type[i] != null) {
if (type[i].equals("int") || type[i].equals("Integer")) {
cs[i] = Integer.TYPE;
} else if (type[i].equals("float") || type[i].equals("Float")) {
cs[i] = Float.TYPE;
} else if (type[i].equals("double") || type[i].equals("Double")) {
cs[i] = Double.TYPE;
} else if (type[i].equals("boolean")
|| type[i].equals("Boolean")) {
cs[i] = Boolean.TYPE;
} else {
cs[i] = String.class;
}
}
}
return cs;
}
/**
* 获取参数Object[]
*/
public Object[] getMethodObject(String[] type, String[] param) {
Object[] os = new Object[type.length];
for (int i = 0; i < os.length; i++) {
if (!type[i].trim().equals("") || type[i] != null) {
if (type[i].equals("int") || type[i].equals("Integer")) {
os[i] = new Integer(param[i]);
} else if (type[i].equals("float") || type[i].equals("Float")) {
os[i] = new Float(param[i]);
} else if (type[i].equals("double") || type[i].equals("Double")) {
os[i] = new Double(param[i]);
} else if (type[i].equals("boolean")
|| type[i].equals("Boolean")) {
os[i] = new Boolean(param[i]);
} else {
os[i] = String.class;
}
}
}
return os;
}
}
实现Java在运行时加载指定的类,并调用指定方法的一个小例子
七、反射有个缺点。就是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。