反射

1、Class类

在面向对象的世界里,万事万物皆对象。类是对象,类是java.lang.Class类的实例对象。

任何一个类都是Class的实例对象,这个实例对象有三种表示方法:

  1. //1、任何一个类都有一个隐含的静态成员class  
  2.     Class c1 = Foo.class;  
  3.   
  4. //2、已经知道该类的对象,通过getClass方法  
  5.     Class c2 = f.getClass();  
  6.   
  7. /** 
  8.     * c1,c2表示了Foo类的类类型(Class Type) 
  9.     * 类是class类的实例对象 
  10.     * 我们称这个对象为该类的的类类 
  11.     */  
  12.   
  13. //3、通过Class.forName方法  
  14.     Class c3 = null;  
  15.     try {  
  16.         c3 = Class.forName("cn.fedomn.demo.Foo");  
  17.     } catch (Exception e) {  
  18.         e.printStackTrace();  
  19.     }  
  20.           
  21. /** 
  22.  * 我们可以通过类的类类型创建该类的对象实例-->通过c1,c2,c3创建Foo类型的对象 
  23.  */  
  24.     try {  
  25.         Foo f2 = (Foo)c1.newInstance();//需要有无参数的构造方法  
  26.     } catch (InstantiationException e) {  
  27.         e.printStackTrace();  
  28.     } catch (IllegalAccessException e) {  
  29.         e.printStackTrace();  
  30.     }            
//1、任何一个类都有一个隐含的静态成员class
	Class c1 = Foo.class;

//2、已经知道该类的对象,通过getClass方法
	Class c2 = f.getClass();

/**
	* c1,c2表示了Foo类的类类型(Class Type)
	* 类是class类的实例对象
	* 我们称这个对象为该类的的类类
	*/

//3、通过Class.forName方法
	Class c3 = null;
	try {
		c3 = Class.forName("cn.fedomn.demo.Foo");
	} catch (Exception e) {
		e.printStackTrace();
	}
		
/**
 * 我们可以通过类的类类型创建该类的对象实例-->通过c1,c2,c3创建Foo类型的对象
 */
	try {
		Foo f2 = (Foo)c1.newInstance();//需要有无参数的构造方法
	} catch (InstantiationException e) {
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		e.printStackTrace();
	}	       

2、动态加载类

首先搞清楚,动态加载类和静态加载类的区别

  • 静态加载类:编译时刻加载类
  • 动态加载类:运行时刻加载类(如功能型类 数据库驱动,需要用时才加载进来)

注意:new 创建对象 是静态加载类,在编译时刻就需要加载所有的可能使用到的类

动态加载类,解决用的时候才加载该类,如下

其中cn.fedomn.demo.Word类implements OfficeAble

  1. public class Office {  
  2.     public static void main(String[] args){  
  3.         try {  
  4.             //动态加载类,在运行时刻加载  
  5.             Class c = Class.forName("cn.fedomn.demo.Word");  
  6.             //通过类型转换,创建该类对象  
  7.             OfficeAble oa = (OfficeAble)c.newInstance();  
  8.             oa.start();  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.     }  
  13. }  
public class Office {
	public static void main(String[] args){
		try {
			//动态加载类,在运行时刻加载
			Class c = Class.forName("cn.fedomn.demo.Word");
			//通过类型转换,创建该类对象
			OfficeAble oa = (OfficeAble)c.newInstance();
			oa.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

3、获取方法信息

  1. public class ClassUtil {  
  2.     public static void printClassMessage(Object obj){  
  3.         //首先获取类的类类型  
  4.         Class c = obj.getClass();  
  5.         //获取类的名称  
  6.         System.out.println("类的名称是:"+c.getName());  
  7.         /** 
  8.          * Method类,方法对象 
  9.          * 一个成员对象就是一个Method对象 
  10.          * getMethods()方法获取的是所以public的函数,包括父类继承而来的 
  11.          * getDeclaredMethods()方法获取的是所有该类自己声明的方法,不问访问权限 
  12.          */  
  13.         Method[] ms = c.getMethods();c.getDeclaredMethods();  
  14.         for(int i=0;i<ms.length;i++){  
  15.             //获取方法返回值类型--->得到方法的返回值类型 的 类类型  
  16.             Class returnType = ms[i].getReturnType();  
  17.             System.out.print(returnType.getName()+" ");  
  18.             //得到方法的名称  
  19.             System.out.print(ms[i].getName()+"(");  
  20.             //获取参数类型--->得到的是参数列表类型 的 类类型  
  21.             Class[] paramTypes = ms[i].getParameterTypes();  
  22.             for(Class class1 : paramTypes){  
  23.                 System.out.print(class1.getName()+",");  
  24.             }  
  25.             System.out.println(")");  
  26.         }  
  27.     }  
  28. }  
public class ClassUtil {
	public static void printClassMessage(Object obj){
		//首先获取类的类类型
		Class c = obj.getClass();
		//获取类的名称
		System.out.println("类的名称是:"+c.getName());
		/**
		 * Method类,方法对象
		 * 一个成员对象就是一个Method对象
		 * getMethods()方法获取的是所以public的函数,包括父类继承而来的
		 * getDeclaredMethods()方法获取的是所有该类自己声明的方法,不问访问权限
		 */
		Method[] ms = c.getMethods();c.getDeclaredMethods();
		for(int i=0;i<ms.length;i++){
			//获取方法返回值类型--->得到方法的返回值类型 的 类类型
			Class returnType = ms[i].getReturnType();
			System.out.print(returnType.getName()+" ");
			//得到方法的名称
			System.out.print(ms[i].getName()+"(");
			//获取参数类型--->得到的是参数列表类型 的 类类型
			Class[] paramTypes = ms[i].getParameterTypes();
			for(Class class1 : paramTypes){
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}
}

4、获取成员变量和构造函数信息

  1. /** 
  2.      *获取成员变量信息  
  3.      */  
  4.     public static void printFieldMessage(Object obj) {  
  5.         Class c = obj.getClass();  
  6.         /** 
  7.          * 成员变量也是对象 
  8.          * java.lang.reflect.Field 
  9.          * Field类封装了关于成员变量的操作 
  10.          * getField()方法获取所有public的成员变量的信息 
  11.          * getDeclaredField()获取的是该类自己声明的成员变量的信息 
  12.          */  
  13.         Field[] fs = c.getDeclaredFields();  
  14.         for(Field field : fs){  
  15.             //得到成员变量的类型的类类型  
  16.             Class fieldType = field.getType();  
  17.             String typeName = fieldType.getName();  
  18.             //得到成员变量的名称  
  19.             String fieldName = field.getName();  
  20.             System.out.println(typeName+" "+fieldName);               
  21.         }  
  22.     }  
  23.       
  24.     /** 
  25.      * 获取对象构造函数的信息 
  26.      */  
  27.     public static void printConMessage(Object obj){  
  28.         Class c = obj.getClass();  
  29.         /** 
  30.          * 构造函数也是对象 
  31.          * java.lang.Constructor中封装了构造函数的信息 
  32.          * getConstructors获取所有的public的构造函数 
  33.          * getDeclaredConstructors得到所有的构造函数 
  34.          */  
  35.         Constructor[] cs = c.getDeclaredConstructors();  
  36.         for(Constructor constructor : cs){  
  37.             System.out.print(constructor.getName()+"(");  
  38.             //获取构造函数的参数列表-->得到参数列表的类类型  
  39.             Class[] paramTypes = constructor.getParameterTypes();  
  40.             for(Class class1 : paramTypes){  
  41.                 System.out.print(class1.getName()+",");  
  42.             }  
  43.             System.out.println(")");  
  44.         }  
  45.     }  
/**
	 *获取成员变量信息 
	 */
	public static void printFieldMessage(Object obj) {
		Class c = obj.getClass();
		/**
		 * 成员变量也是对象
		 * java.lang.reflect.Field
		 * Field类封装了关于成员变量的操作
		 * getField()方法获取所有public的成员变量的信息
		 * getDeclaredField()获取的是该类自己声明的成员变量的信息
		 */
		Field[] fs = c.getDeclaredFields();
		for(Field field : fs){
			//得到成员变量的类型的类类型
			Class fieldType = field.getType();
			String typeName = fieldType.getName();
			//得到成员变量的名称
			String fieldName = field.getName();
			System.out.println(typeName+" "+fieldName);				
		}
	}
	
	/**
	 * 获取对象构造函数的信息
	 */
	public static void printConMessage(Object obj){
		Class c = obj.getClass();
		/**
		 * 构造函数也是对象
		 * java.lang.Constructor中封装了构造函数的信息
		 * getConstructors获取所有的public的构造函数
		 * getDeclaredConstructors得到所有的构造函数
		 */
		Constructor[] cs = c.getDeclaredConstructors();
		for(Constructor constructor : cs){
			System.out.print(constructor.getName()+"(");
			//获取构造函数的参数列表-->得到参数列表的类类型
			Class[] paramTypes = constructor.getParameterTypes();
			for(Class class1 : paramTypes){
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}

5、方法反射操作

method.invoke(对象,参数列表)

  1. public class MethodDemo1 {  
  2.     public static void main(String args[]){  
  3.         //要获取print(int,int)方法  
  4.         //1、要获取一个方法就是获取类的信息,获取类的信息 首先获取类的类类型  
  5.         A a = new A();  
  6.         Class c = a.getClass();  
  7.         /** 
  8.          * 2、获取方法 名称和参数列表来决定 
  9.          * getMethod获取的是public方法 
  10.          * getDeclaredMethod获取自己声明的方法 
  11.          */  
  12.         try {  
  13.             Method m = c.getMethod("print", int.class,int.class);  
  14.             //方法的反射操作  
  15.             //用m对象来进行方法调用  
  16.             //等同于a.print(10, 20);  
  17.             //方法如果没有返回值返回null,有返回值返回具体返回值  
  18.             try {  
  19.                 Object o = m.invoke(a, 10,20);  
  20.             } catch (IllegalAccessException | IllegalArgumentException  
  21.                     | InvocationTargetException e) {  
  22.                 e.printStackTrace();  
  23.             }  
  24.         } catch (NoSuchMethodException e) {  
  25.             e.printStackTrace();  
  26.         } catch (SecurityException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30. }  
  31.   
  32. class A{  
  33.     public void print(int a,int b){  
  34.         System.out.println(a+b);  
  35.     }  
  36.     public void print(String a,String b){  
  37.         System.out.println(a.toUpperCase()+","+b.toLowerCase());  
  38.     }  
  39. }  
public class MethodDemo1 {
	public static void main(String args[]){
		//要获取print(int,int)方法
		//1、要获取一个方法就是获取类的信息,获取类的信息 首先获取类的类类型
		A a = new A();
		Class c = a.getClass();
		/**
		 * 2、获取方法 名称和参数列表来决定
		 * getMethod获取的是public方法
		 * getDeclaredMethod获取自己声明的方法
		 */
		try {
			Method m = c.getMethod("print", int.class,int.class);
			//方法的反射操作
			//用m对象来进行方法调用
			//等同于a.print(10, 20);
			//方法如果没有返回值返回null,有返回值返回具体返回值
			try {
				Object o = m.invoke(a, 10,20);
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				e.printStackTrace();
			}
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}
}

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());
	}
}

6、通过反射了解集合泛型的本质

注意:反射的操作(class method field)都是在编译时候的操作,是运行时刻执行的

下例中:对ArrayList<String>插入int类型的值,就是利用反射invoke,绕过编译实现插入。

  1. public static void main(String args[]){  
  2.         ArrayList list1 = new ArrayList();  
  3.         ArrayList<String> list2 = new ArrayList<String>();  
  4.           
  5.         //list2.add(20);错误只能插入String  
  6.         list2.add("hello");  
  7.           
  8.         Class c1 = list1.getClass();  
  9.         Class c2 = list2.getClass();  
  10.         System.out.println(c1==c2);  
  11.         //反射的操作都是编译之后的操作  
  12.         /** 
  13.          * c1==c2返回true,说明编译之后集合的泛型是去泛型化的 
  14.          * Java中集合的泛型,是防止错误输入的,只在编译阶段有效  编译后就无效了 
  15.          * 验证:通过方法的反射来操作,绕过编译 
  16.          */  
  17.         try {  
  18.             Method m = c2.getMethod("add", Object.class);  
  19.             m.invoke(list2, 10);//绕过编译操作 就绕过了泛型 插入成功  
  20.             //这个时候就不能for-each遍历了  
  21.             System.out.println(list2);  
  22.         } catch (Exception e) {  
  23.         }  
  24.     }  
原文地址:https://www.cnblogs.com/caogang/p/4382561.html