反射

来源:互联网 发布:佳明飞耐时3软件 编辑:程序博客网 时间:2024/06/11 06:13

学习imooc反射内容总结

1、Class类

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

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

//1、任何一个类都有一个隐含的静态成员classClass 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

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、获取方法信息

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、获取成员变量和构造函数信息

/** *获取成员变量信息  */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(对象,参数列表)

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,绕过编译实现插入。

public static void main(String args[]){ArrayList list1 = new ArrayList();ArrayList<String> list2 = new ArrayList<String>();//list2.add(20);错误只能插入Stringlist2.add("hello");Class c1 = list1.getClass();Class c2 = list2.getClass();System.out.println(c1==c2);//反射的操作都是编译之后的操作/** * c1==c2返回true,说明编译之后集合的泛型是去泛型化的 * Java中集合的泛型,是防止错误输入的,只在编译阶段有效  编译后就无效了 * 验证:通过方法的反射来操作,绕过编译 */try {Method m = c2.getMethod("add", Object.class);m.invoke(list2, 10);//绕过编译操作 就绕过了泛型 插入成功//这个时候就不能for-each遍历了System.out.println(list2);} catch (Exception e) {}}









0 0