Java:反射机制
概念
根据oracle中的一篇文章Using Java Reflection中说明,还是98年发表的。
反射是Java编程语言的一项功能。它允许一个正在执行的程序去检查或自我"反省",并且还可以修改内部的程序属性。例如,它可以获取一个类的所有成员的名字并显示它们。
有一个反射的具体使用便是JavaBeans,它可以通过构建工具让软件组件被可视化的修改。当Java组件(classes)动态加载后,这个工具可以通过反射获取它们的属性。
我们其实只需这样简单理解就好了。
简单例子
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[])
{
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
阐述例子
反射的各种类,像 Method 这样的类都可以在 java.lang.reflect 包里找到。
从一个你需要检查的类中获取 java.lang.Class 对象 (java.lang.Class 是用来表现正在运行程序的类和接口) 其中一个获取 Class 对象的方法如下面所示:
Class c = Class.forName("java.lang.String"); //获取 String 的 Class 对象
Class c = int.class; //获取整型的Class对象
//or
Class c = Integer.TYPE;
通过这个类获取已声明的所有方法的列表,像 getDeclaredMethods 方法一样;
一旦这信息握在手里,就可以用反射API去检查这信息。以下通过文本显示第一个方法;
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
模拟 instanceof 操作符:( * 类名和文件名保持一致,规范来讲类名需要首字母大写)
class A {}
public class instance1 {
public static void main(String args[]) {
try {
Class cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37));
System.out.println(b1);
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
} catch (Throwable e) {
System.err.println(e);
}
}
}
找出类的方法
反射最有价值的并且也是最基础的使用是找出定义在类里面的方法,如下代码:
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);
}
}
}
找出类的字段
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);
}
}
}
执行类的方法
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); //获取方法名为"add"的方法,并且加入自定义形参
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); //加入实参,执行add方法,返回参数。
Integer retval = (Integer) retobj;
System.out.println(retval.intValue()); //打印输出结果
} catch (Throwable e) {
System.err.println(e);
}
}
}
执行类的构造函数
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);
}
}
}
修改字段的值
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"); //获取filed2类中变量名为d的字段
field2 f2obj = new field2(); //实例化自定义类
System.out.println("d = " + f2obj.d);
fld.setDouble(f2obj, 12.34); //在指定的已实例化filed2类中修改其值
System.out.println("d = " + f2obj.d);
} catch (Throwable e) {
System.err.println(e);
}
}
}
数组的使用
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);//实例化长度为10的字符串
Array.set(arr, 5, "this is a test"); //设置下标在5的值为"this is a test"
String s = (String) Array.get(arr, 5);//获取下标在5的值
System.out.println(s);
} catch (Throwable e) {
System.err.println(e);
}
}
}
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); // 第二参数为维度,这里创建了5x10x15
// int数组
Object arrobj = Array.get(arr, 3); // 获取10x15数组
Class cls = arrobj.getClass().getComponentType();
System.out.println(cls);
arrobj = Array.get(arrobj, 5); // 获取15一维数组
Array.setInt(arrobj, 10, 37); // 设置[3][5][10] 的值为37
int arrcast[][][] = (int[][][]) arr;
System.out.println(arrcast[3][5][10]);
}
}
这里的数组的类型都是动态得被创建了,而不是在编译期。
总结
反射对于特定功能需求的实现很有用,通过名字可以检索类和数据结构,允许在运行期审查程序自身信息。