java 反射
1.反射基础——Class类
Java把一个类中与数据类型相关的信息封装起来,并提供一些方法,构成了Class类。
这些信息如:几个构造函数?是否实现了xxx接口?父类是不是xxx?
Class类的实例提供了特定数据类型的相关信息,一个Class类的对象实际上表示的是一种类型。
获取Class类实例的三种方式 :
(1)
Employee e;
Class cl=e.getClass();
(2)
Class c1=Class.forName(“java.util.Date”)
(3)
T.Class,如 Class c1=int.class; Class c2=Double[].class;
所谓“反射(Reflection)”,就是把Java类中的各种成份映射成相应的另外一些特殊的Java类的实例,从而允许程序在运行时动态地完成一些工作:比如动态装载类型并创建实例,查询类的成员信 息,动态地调用方法等
public class TestMain {
public static void main(String[] args){
showClassInfor("test".getClass());
System.out.println();
showClassInfor(int.class);
System.out.println();
int[] arr=new int[10];
showClassInfor(arr.getClass());
}
private static void showClassInfor(Class<?> c){
System.out.println("类名称:"+c.getName());
System.out.println("是否为接口:"+c.isInterface());
System.out.println("是否为基本类型:"+c.isPrimitive());
System.out.println("是否为数组对象:"+c.isArray());
Class<?> parent=c.getSuperclass();
if(parent!=null)
System.out.println("父类名称:"+parent.getName());
Package p=c.getPackage();
if(p!=null)
System.out.println("所在包名:"+p.getName());
}
}
判断对象所属类型:
public class TestMain {
public static void main(String[] args){
String str="aaa";
if(str.getClass().getName()=="java.lang.String"){
System.out.println("str.getClass().getName()==String");
}
if(str.getClass()==String.class){
System.out.println("str.getClass()==String.class");
}
}
}
输出:
str.getClass().getName()==String
str.getClass()==String.class
基本数据类型,比如int,float等,也有一个对应的Class实例,它并不等于包装类的Class实例,包装类另提供了一个TYPE字 段,向外界返回它所包装的基本数据类型的Class实例。所以int.class==Integer.TYPE,其值为true。
指定类所拥有的属性、方法、构造函数特性分别由java.lang.reflect包中的Field、Method和Constructor三个类来表达,以下示例为查询类成员代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestMain {
public static void main(String[] args){
try{
Class<?> c=Class.forName("java.util.Date");
Class<?> superc=c.getSuperclass();
System.out.println("class "+c.getName());
if(superc!=null&&superc!=Object.class)
System.out.println("extends "+superc.getName());
System.out.print("\n{\n");
printConstructors(c);
System.out.println();
printMethods(c);
System.out.println();
printFields(c);
System.out.println("}");
}catch (ClassNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void printConstructors(Class<?> cl){
Constructor<?>[] constructors = cl.getDeclaredConstructors();
for (Constructor<?> c : constructors){
String name = c.getName();
System.out.print(" " + Modifier.toString(c.getModifiers()));
System.out.print(" " + name + "(");
Class<?>[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++){
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
public static void printMethods(Class<?> cl) {
Method[] methods=cl.getDeclaredMethods();
for(Method m:methods){
Class<?> retType=m.getReturnType();
String name=m.getName();
System.out.print(" "+Modifier.toString(m.getModifiers()));
System.out.print(" "+retType.getName()+" "+name+"(");
Class<?>[] paramTypes=m.getParameterTypes();
for(int j=0;j<paramTypes.length;j++){
if(j>0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
public static void printFields(Class<?> cl){
Field[] fields = cl.getDeclaredFields();
for (Field f : fields){
Class<?> type = f.getType();
String name = f.getName();
System.out.print(" " + Modifier.toString(f.getModifiers()));
System.out.println(" " + type.getName() + " " + name + ";");
}
}
}
动态创建对象的典型方法:
基本思路: 使用构造方法对象或Class对象的newInstance()方法动态创建指定类型的对象
import java.lang.reflect.*;
import java.util.List;
public class TestMain {
public static void main(String[] args) {
invokeConstructorNoArgu();
invokeConstructorWithArgu();
}
//调用无参构造函数创建对象
private static void invokeConstructorNoArgu() {
try {
Class<?> c = Class.forName("java.util.ArrayList");
List list = (List) c.newInstance(); // 直接调用Class对象的newInstance方法创建对象
for (int i = 0; i < 5; i++) {
list.add("element " + i);
}
for (Object o : list.toArray()) {
System.out.println(o);
}
} catch (ClassNotFoundException e) {
System.out.println("找不到指定的类");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//调用有参构造函数创建对象
private static void invokeConstructorWithArgu() {
try {
Class<?> c = Class.forName("learning.Student");
// 取得对应参数列的构造函数 ,仅适用于JDK1.5及以上版本
Constructor<?> constructor =
c.getConstructor(String.class,int.class);
// 指定实参
Object[] argObjs = new Object[2];
argObjs[0] = "jxl";
argObjs[1]=90;
//创建对象
Object obj=constructor.newInstance("jxl",90);
// 检查结果
System.out.println(obj);
} catch (ClassNotFoundException e) {
System.out.println("找不到类");
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
System.out.println("没有所指定的方法");
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class Student {
private String name;
private int score;
public Student() {
name = "N/A";
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public void setName(String name) {
this.name = name;
}
public void setScore(int score) {
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public String toString() {
return name + ":" + score;
}
}
利用反射存取对象字段:
package learning;
import java.lang.reflect.*;
public class TestMain {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("learning.TestField");
Object targetObj = c.newInstance();
Field testInt = c.getField("testInt");
//注意testInt引用的是一个Field对象,它并不直接关联targetObject对象。
//所以以下setInt方法的第一个参数要指明需要设置字段值的那个对象
testInt.setInt(targetObj, 99);
Field testString = c.getField("testString");
testString.set(targetObj, "jxl");
System.out.println(targetObj);
//访问类的私有成员
Field testPrivate=c.getDeclaredField("privateValue");
testPrivate.setAccessible(true); //允许访问私有成员
testPrivate.set(targetObj, 100);
System.out.println(testPrivate.get(targetObj));
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("没有指定类");
} catch (ClassNotFoundException e) {
System.out.println("找不到指定的类");
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
System.out.println("找不到指定的域成员");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class TestField {
public int testInt;
public String testString;
public String toString() {
return testInt + ":" + testString;
}
private int privateValue=0;
}
使用反射调用方法:
package learning;
import java.lang.reflect.*;
import java.util.Map;
public class TestMain {
public static void main(String[] args) throws Exception{
// 调用实例对象的实例方法
System.out.println("调用String对象的实例方法charAt(int index)");
Method charat = String.class.getMethod("charAt", int.class);
System.out.println(charat.invoke("hello", 1));
// get method pointers to the square and sqrt methods
Method square = TestMain.class.getMethod("square", double.class);
Method sqrt = Math.class.getMethod("sqrt", double.class);
// print tables of x- and y-values
printTable(1, 10, 10, square);
printTable(1, 10, 10, sqrt);
}
public static double square(double x) {
return x * x;
}
public static void printTable(double from, double to, int n, Method f) {
// print out the method as table header
System.out.println(f);
// construct formatter to print with 4 digits precision
double dx = (to - from) / (n - 1);
for (double x = from; x <= to; x += dx) {
try {
// 第一个参数为对象,第二个参数为方法参数,为null时表示要调用静态方法
double y = (Double) f.invoke(null, x);
System.out.printf("%10.4f | %10.4f%n", x, y);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
需要直接调用反射技术“干活”的场景通常不多,但在实际开发中用到的许多开发框架在内部使用了反射技术完成工作, 因此,学习与了解反射技术,对看懂各种开发框架源代码是必需的
参考:
金旭亮Java编程系列