无论是在C#还是Java(平常常玩儿的就这俩,所以这么举例,别的语言也雷同!),为了获取类的灵活性,我们会时常使用反射,将类的信息写入配置,通过运行时候动态获取类,类的方法,字段,等等。
在Java中,我们通常是一个思路来动态访问类信息的,先获取类的Class 类,这个Class指明了是哪个类,然后通过获取到的Class get各种类信息。
一,获取Class类
public class ClassDemo1 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//Foo的实例对象如何表示
Foo foo1=new Foo();//foo1就表示出来了
//Foo这个类 也是一个实例对象,Class类的实例对象如何表示
//任何一个类都是Class类的实例对象,这个实例对象有3中表示方式
/*第一种表示方式--》实际在告诉我们任何一个类都有一个隐含的静态成员变量*/
Class c1=Foo.class;
/*第二种表达方式:已知该类的对象,通过getClass方法*/
Class c2=foo1.getClass();
/*官网:c1/c2表示了Foo类的类类型(class type)
* 类也是对象,是class类的实例对象
* 这个对象我们成为该类的类类型
* */
/*不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个对象*/
System.out.println(c1==c2);//true
//第三种表达方式
Class c3=null;
c3=Class.forName("ShuiTian.NaiLuo.Reflect.Foo");
System.out.println(c3);
/*我们完全可以通过类的类类型创建该类的对象
* 通过c1 or c2 or c3创建父的实例
*
* */
Foo foo=(Foo)c1.newInstance();//使用newInstance需要有无参数的构造方法
}
}
class Foo{}
主要有上面三种方式:第一种通过类的静态变量获取;第二种通过实例的getClass方法获取,第三种通过一个字符串来动态加载;仔细观察这三种方式,感觉最后一种用的还是比较多的,比如为数据库加载驱动的时候,配置Spring的时候,这种方式使得类的装配更具有灵活性。例如,我们可以使用这种方式在运行时候动态加载类:
public class DynamicLoadClass { public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException{ String animalName="Cat"; Animal animal = null; switch (animalName){ case "Cat": animal=(Animal)Class.forName("ShuiTian.NaiLuo.Reflect.Cat").newInstance(); break; case "Dog": animal=(Animal)Class.forName("ShuiTian.NaiLuo.Reflect.Dog").newInstance(); break; } System.out.println(animal); System.out.println(animal.getClass().getSimpleName()); } } interface Animal{} class Cat implements Animal{} class Dog implements Animal{}
二,获取类信息
当我们使用各种方法获取到类class之后,就可以使用这个class访问类的信息了。
1,获取类的方法信息
/* * 打印类的信息,包括类的成员函数,类的成员变量 参数是一个对象,该对象的所属信息 */ public static void printClassMethodMessage(Object obj) { // 要获取类的信息,首先要获取类的类类型 class type Class c = obj.getClass();// 传递的是哪个子类的对象 // 获取类的名称 System.out.println(c.getName()); /* * Method类是方法对象 一个成员方法就是一个Method对象 getMethods获取的是所有的public函数,包括从父类继承而来的 * c.getDeclaredMethods()获取的是所有该类声明的方法,不问访问权限 */ Method[] ms = c.getMethods(); //获取类的方法数组 for (Method method : ms) { //对类的方法数组进行循环,在循环中获取函数返回值信息及参数信息,也可以对方法进行动态调用 // 得到方法的返回值类型的类类型 Class returnType = method.getReturnType(); System.out.print(returnType.getName() + "("); // 得到方法的名称 System.out.print(method.getName()); // 获取方法的参数类型--->得到的是参数列表的类型的类类型 Class[] paramTypes = method.getParameterTypes(); for (Class c1 : paramTypes) { System.out.print(c1.getName() + ","); } System.out.println(")"); } printFieldMessage(obj); }
2,获取类的成员变量的信息
/*获取类的field信息*/ public static void printFieldMessage(Object obj) { Class c=obj.getClass(); /* * 成员变量也是对象 java.lang.reflect.field Field类封装了关于成员变量的操作 * getFields方法获取的是所有public成员变量的信息 getDeclaredFields获取的是该类自己声明的成员 */ Field[] fs = c.getDeclaredFields(); for (Field field : fs) { /* 得到成员变量的类类类型 */ Class fieldType = field.getType(); String typeName = fieldType.getName(); /* 得到成员变量的名称 */ String fieldName = field.getName(); System.out.println(fieldType + "," + fieldName); } }
3,获取对象的构造函数的信息
/*打印对象的构造函数的信息*/
public static void printConMessage(Object obj){
Class c=obj.getClass();
/*
* java.lang.constructors封装了构造函数的信息
* getConstructors()获取了所有的public的构造函数的信息
* getDeclaredConstructors:得到了自己声明的构造函数
* */
Constructor[] cs =c.getDeclaredConstructors(); //获取构造函数数组
for(Constructor con :cs ){ //分别对各个构造函数进行遍历
System.out.print(con.getName()+"(");
//获取构造函数的参数列表----得到的是参数列表的类类型
Class[] paramTypes=con.getParameterTypes(); //得到构造函数的参数列表
for(Class param:paramTypes){
System.out.print(param.getName()+",");
}
System.out.println(")");
}
}
4,通过反射动态调用方法
/*
* 测试方法的反射
*
* */
public class MethodDemo1 {
public static void main(String[] args) throws InstantiationException,
IllegalAccessException, ClassNotFoundException,
NoSuchMethodException, SecurityException, IllegalArgumentException,
InvocationTargetException {
// 获取print(int,int)方法
Class a = Class.forName("ShuiTian.NaiLuo.Reflect.A");
/*
* 获取方法名称,参数列表。。。 getMethod:获取的是public的方法 getDeclaredMethod:获得的是自己声明的方法
*/
Method m = a.getMethod("print", new Class[] { int.class, int.class });
/*
* 方法的反射操作 使用m对象来进行方法的调用 方法返回值问题 1,无返回值返回null 2,有返回值,返回具体值
*/
m.invoke(a.newInstance(), 10, 10);
// m.invoke(a,10,10);
System.out.println("==========分割线============");
Method m2 = a.getMethod("print", String.class, String.class);
m2.invoke(a.newInstance(), "lhc", "水田");
}
}
class A {
public void print(int a, int b) {
System.out.println(a + b);
}
public void print(String a, String b) {
System.out.println(a.toUpperCase() + "," + b.toLowerCase());
}
}
额,有了这个基础,再去看spring的源码,估计就差不多能看懂了。