Class对象与反射机制的学习
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Class对象与反射机制的学习相关的知识,希望对你有一定的参考价值。
刚对java反射机制进行了学习,在此做一个总结。
总结分为三部分,一.介绍java的Class类概念,二.进一步介绍通过Class类我们可以获取关于类的哪些信息,三.反射方法的基本操作
在这之前,我们的脑海中一定要牢记如下一句话:“万物皆对象!” 这句话可以贯穿本节始终,帮助我们站在一个高度理解这部分内容。
一.java的Class类概念
万物皆对象,那么对于面向对象语言java,我们就可以自然补充出下一句,万物皆有类,因为每个对象实例都有他所属于的类别。
那么对于我们代码中的String, Date,Time类型也好,还是我们自定义的Demo等类也好,这些类换个角度来看也是一种对象,而这些特殊对象所隶属的类别就是Class类。(注:全路径为java.lang.Class)
Class类实例化的对象即类对象,java中为每个类都定义了其独有的类对象,类对象包含了该类的一些信息和操作方法。
在这里区分两个概念,“类对象”和“类的对象”,我们本章研究的是前者,拿String类举例子来说明:
String str = "abc"; //str是String的“类的对象” Class c = String.class; //c是String的“类对象”
明确了类对象的概念之后,介绍一下我们如何获取类对象。我们在包com.classtest下建立一个类DemoTest,那么有三种方法可以获得其类对象。
//获取类对象的第一种方式(通过类) Class c1 = DemoTest.class; //获取类对象的第二种方式(通过类实例) DemoTest dt = new DemoTest(); Class c2 = dt.getClass(); //获取类类型的第三种方式(需要捕获异常),能够动态加载类的核心方法 Class c3 = null; try{ c3 = Class.forName("com.classtest.DemoTest"); }catch(ClassNotFoundException e){ e.printStackTrace(); }
这里要特别指出的是,采用前两种方法,java在编译时就需要检测DemoTest类已经存在,否则编译错误,而第三种获得类对象的方法,只有在运行时才会判断使用的com.classtest.DemoTest类是否存在,否则报错,也因此需要加上异常判断。注意由于在运行时才判断获得哪个类的类对象,因此第三种方法是实现动态加载类的核心方法。
二.通过Class类对象我们可以获得的信息
如果我们获得了一个类的类对象,那么我们就可以利用它获得此类的实例,类的类名,此类包含的方法名,此类的成员变量,此类的构造函数等丰富的信息。下面逐一说明。
1)根据类的类对象获得该类的实例
try{ //调用类对象的newInstance()方法,获得实例dt1,注意需要强制类型转换 DemoTest dt1 = (DemoTest)c3.newInstance(); dt1.show();
//注意捕获异常 }catch(InstantiationException e){ e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }
2)根据类对象获得该类的类名
//调用类对象的getName方法 Class c = DemoTest.class; String className = c.getName());
3)根据类对象获得该类的方法
万物皆对象,方法也是对象,其所属的类型为 java.lang.reflect.Method
此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的方法
/* * 打印类的名称,类的方法信息 * 方法也是一种对象,方法对象的类是java.lang.reflect.Method * @param ob 所测试类的对象 */ public static void getClassMethods(Object ob){ Class c = ob.getClass();
//类对象的getMethods方法返回 类包含方法对象的数组 Method[] methods = c.getMethods(); System.out.println("当前类的类名为:"+c.getName()); System.out.println("类公开方法有:"); for(int i=0;i<methods.length;i++){ //得到方法的名称 System.out.print(methods[i].getName()+"("); //得到方法的参数名称 Class[] paramTypes = methods[i].getParameterTypes(); for(Class pt:paramTypes){ System.out.print(pt.getName()+","); } System.out.println(")"); } }
4)根据类对象获得该类包含的成员变量
万物皆对象,成员变量也是对象,其所属的类型为 java.lang.reflect.Field
此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的成员变量
/* * 打印类的成员变量 * 成员变量也是对象,属于java.lang.reflect.Fild类 * Fild类封装了关于成员变量的操作 * @param ob */ public static void getClassField(Object ob){ Class c = ob.getClass();
//getFile返回类的成员变量对象数据 //Field[] fields = c.getFields(); Field[] fields = c.getDeclaredFields(); System.out.println("当前类的类名为:"+c.getName()); System.out.println("类的成员变量有:"); for(Field field:fields){ //获取成员变量的类类型 Class ftype = field.getType(); String className = ftype.getName(); String fieldName = field.getName(); System.out.println(className+" "+fieldName); } }
5)根据类对象获取对应类的构造方法
万物皆对象,构造方法也是对象,其所属的类型为 java.lang.reflect.Constructor
此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的构造方法
/* * 获取类的所有构造函数的信息 * 构造函数也是对象,构造函数属于类java.lang.reflect.Constructor * @param ob */ public static void getConstructors(Object ob){ Class c = ob.getClass(); Constructor[] cons = c.getDeclaredConstructors(); System.out.println("当前类的类名为:"+c.getName()); System.out.println("类的构造方法有:"); for(int i=0;i<cons.length;i++){ //得到方法的名称 System.out.print(cons[i].getName()+"("); //得到方法的参数名称 Class[] paramTypes = cons[i].getParameterTypes(); for(Class pt:paramTypes){ System.out.print(pt.getName()+","); } System.out.println(")"); } }
三.方法反射的基本操作
第二部分可以看出通过类对象我们可以获得关于类的一系列信息,本部分我们介绍通过获取的方法对象信息来反射调用类的方法。
反射这里涉及两个问题1.如何获取特定的方法对象2.通过方法对象如何调用类的方法。
1.获取特定的方法对象
首先我们在自定义类型DemoTest类中定义两个方法。
//定义一个无参方法show public void show(){ System.out.println("this is a DemoTest"); } //定义一个有参方法add public int add(int a,int b){ return a+b; }
然后获得该类的类对象,类对象有方法getMethod可以获得指定的方法对象,如下代码所示:
Class c = DemoTest.class //获得无参方法show Method m1 = c.getMethod("show"); //获得有参方法add Method m2 = c.getMethod("add", int.class,int.class);
2.通过方法对象调用方法,方法对象的invoke方法可以调用对应的方法,注意获取方法对象和调用均有可能抛出异常,因此合并写为如下代码:
try { Class c = DemoTest.class; //获得无参方法show Method m1 = c.getMethod("show"); //获得有参方法add Method m2 = c.getMethod("add", int.class,int.class); DemoTest demoTest = new DemoTest(); //invoke方法来调用,需要传一个实例demoTest m1.invoke(demoTest); Object result = m2.invoke(demoTest, 2,3); System.out.println(result); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
这样就完成了通过方法对象反射调用对应的方法。
自己的理解:程序员通过类对象,方法对象,成员变量对象,构造方法对象等进行程序操作的行为,相对于类,方法,成员变量,构造方法来说,就是反射操作。反射操作已经跳过了java代码,而类似是在直接操作编译后的.class代码,因此反射相关的程序可以动态加载一些资源,仅仅当运行期会查找使用资源是否存在且合理,而报出错误。
以上是关于Class对象与反射机制的学习的主要内容,如果未能解决你的问题,请参考以下文章