Java反射整理

  1. 云栖社区>
  2. 博客>
  3. 正文

Java反射整理

soledad_lhc 2016-04-05 15:19:00 浏览1428
展开阅读全文


    

   无论是在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的源码,估计就差不多能看懂了。







网友评论

登录后评论
0/500
评论
soledad_lhc
+ 关注