Java反射机制——学习总结
sagt4092
8年前
<p>前几天上REST课,因为涉及到Java的反射机制,但是老师当时只是带过一下,没有细讲,周末找了些资料来学习,现在总结一下,加深印象。</p> <h3><strong>什么是反射机制?</strong></h3> <p>参考百度百科对java反射机制的定义:</p> <p>“JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的 反射机制。”</p> <p>我们通过一些例子,更好理解反射机制。</p> <p><strong>Class类</strong></p> <p>我们知道Java是一门面向对象语言,在Java的世界里,万物皆为对象,比如我们有一个Person类:</p> <pre> <code class="language-java">public class Person { } </code></pre> <p>我们创建一个Person类的实例,Person person = new Person(); 那么这个person,就是Person类的实例对象。</p> <p>那么既然万物都为对象,所以类也是对象。</p> <p>类是什么的对象呢? 类是Class类的对象 ,表示方式有三种:</p> <pre> <code class="language-java">//第一种,任何一个类都有一个隐含的静态成员变量class Class c1 = Person.class; //第二种,已经知道该类的对象,通过getClass()获得 Class c2 = person.getClass(); //第三种,Class类的forName()方法 Class c3 = Class.forName("Person"); //这里,c1,c2,c3都是Class类的实例,我们称c1, c2 ,c3为Person类的类类型 //不难看出,c1 == c2结果是true, c2 == c3结果也是true </code></pre> <p>通过类的类类型,我们经常会用到的方法就是newInstance()方法,通过该方法可以创建该类的实例:</p> <pre> <code class="language-java">Person personA = new Person(); //直接new一个实例 Person personB = Person.class.newInstance(); //通过newInstance()方法获得Person的实例 //在学习JAVAEE时候,newInstance()方法我们最常见于获取数据库驱动 Class.forName("com.mysql.jdbc.Driver").newInstance(); //需要注意的是,在使用newInstance()方法的前提是该类必须要有无参构造方法 </code></pre> <p><strong>动态加载类:</strong></p> <p>编译时刻加载类称为静态加载,运行时刻加载类称为动态加载,使用new方法新建实例即为静态加载类,在编译时候就要加载全部类。这里我们举一个例子:</p> <p>为了更好的区分编译和运行,我们不适用IDE工具,而使用记事本来实现这个例子:</p> <pre> <code class="language-java">//我们举女娲造人的例子,创建一个CreatePerson类 public class CreatePerson { public static void main(String[] args) { if(args[0].equalsIgnoreCase("man")) { //如果从命令行传入的参数为man 则创建Man的实例并调用say()方法 new Man().say(); } if(args[0].equalsIgnoreCase("woman")) { //如果从命令行传入的参数为woman 则创建Woman的实例并调用say()方法 new Woman().say(); } } } //CreatePerson类用到了2个类,分别是Man和Woman。 //但是我们现在只创建Man类 public class Man { public void say() { System.out.println("I am a man !"); } } </code></pre> <p>我们在CMD中编译CreatePerson,看看会发生什么:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/80fb359d696f815505543fbf5160a2f1.png"></p> <p>提示我们找不到Woman这个类。 这就是静态加载,在编译时刻需要加载全部类。那么问题来了,如果我要写一个程序,里面有100个功能,这100个功能分别由100个类实现,那么一旦缺少一个类,这整个程序是不是就不能用了。</p> <p>为了解决这个问题,我们可以使用动态加载。我们把上面这个例子改一下:</p> <pre> <code class="language-java">//创建一个Person接口 public interface Person { void say(); } //修改Man类,继承Person接口 public class Man implements Person{ public void say() { System.out.println("I am a man !"); } } //修改CreatePerson类,实现动态加载类 public class CreatePerson{ public static void main(String[] args) { try{ //动态加载类 Class c = Class.forName(args[0]); //通过类的类类型,创建该类实例对象 Person person = (Person)c.newInstance(); person.say(); } catch(Exception e) { e.printStackTrace(); } } } </code></pre> <p>这个时候,我们再进行编译:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/ed67a23b2e01938896ec146df81007e1.png"></p> <p>没有报错了,那么我们继续把Man编译,再运行一下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/935cc388bc9b76b77903c6102fecf0b5.png"></p> <p>如果我们在命令行中输入的参数是Woman呢?</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/bfd012a09ba681dec0044753712a86fe.png"></p> <p>抛出ClassNotFoundException异常。因为我们并没有创建Woman类,所以如果以后需要创建Woman类实例,我们只需要新建一个Woman类,并实现Person接口就行了。</p> <h3><strong>通过反射机制,获得类的信息</strong></h3> <p>在Java反射机制的定义中有:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。下面是一个实例:</p> <pre> <code class="language-java">import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ClassUtil { /** * 获取成员函数的信息 */ public static void getClassMethodMessage(Object obj) { Class c = obj.getClass(); //获取类的名称 //System.out.println(c.getName()); /** * * Method类,方法对象 *getMethods方法获得所有public的方法,包括继承而来 *getDeclaredMethods是获取该类自己的声明的方法 */ Method[] ms = c.getMethods(); 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(")"); } } public static void getFieldMessage(Object obj) { Class c = obj.getClass(); /** * 成员变量也是对象 * java.lang.reflect.Field * */ 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(); /** * 构造函数也是对象 * */ Constructor[] cs = c.getConstructors(); for (Constructor constructor : cs) { System.out.print(constructor.getName() + "("); //获取构造函数参数列表------>参数列表的参数类型 Class[] paramType = constructor.getParameterTypes(); for (Class class1 : paramType) { System.out.print(class1.getName() + ","); } System.out.println(")"); } } public static void main(String[] args) { String s = "hello"; getFieldMessage(s); ClassUtil.printConMessage(s); getClassMethodMessage(s); } } </code></pre> <h3><strong>方法的反射操作</strong></h3> <p>可以通过方法的反射操作实现方法的调用:</p> <pre> <code class="language-java">import java.lang.reflect.Method; public class MethodDemo1 { public static void main(String[] args) { //要获取print(int, int) //要获取类的方法就要获取类的信息,获取类的信息就要获取类的类类型 A a1 = new A(); Class c = a1.getClass(); //2,获取方法 名称和参数列表 //getMethod获取的是public的方法 try { Method m = c.getDeclaredMethod("print", int.class,int.class); //方法的反射操作 //a1.print(10, 20);方法的反射操作,用m来进行方法调用和前者效果一致 Object obj = m.invoke(a1, 10,20);//如果方法有返回值返回值,没有就null } catch (Exception 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.toUpperCase()); } } </code></pre> <p>以上就是我对Java反射机制的学习和理解。</p> <p> </p> <p>来自:http://www.cnblogs.com/zhuangcy4567/p/5972947.html</p> <p> </p>