反射

来源:互联网 发布:爱情动作片 下载软件 编辑:程序博客网 时间:2024/05/23 19:59

反射让程序在运行时能够加载类,对于框架是一项非常实用的技术,而且为了学习框架必须了解其中的一些原理。

一、对构造函数的反射,得到构造函数,然后可以创建一个该类的实例。改构造函数可以是无参和有参的,下文都有举例。

二、对方法的反射,知道某一个方法名,可以很方便的利用反射技术来调用该方法,其意义在于即使不知道方法名,我们可以在配置文件中进行声明,而相当于已知。

对于一个陌生的类,我们可以先通过Class类的getDeclaredMethods()来获得所有自定义的类,然后通过某些方法来获取其修饰符,型参列表等,这样我们也可以了解一下这个类的大致用途了。

对于main的反射,有着些许不同,因为java兼容1.4的缘故,普通思想会出错,所以需要当作特例来对待,参见下面的例子。

三、域也可以通过反射来获得的。

四、所有私有域、方法、构造函数都可以通过setAccess方法来激活、或者修改。

package info.dyndns.oszc.reflection;public class Person {private String name;public Person(){System.out.println("person in no argu constructor");}public Person(String name){this.name = name;}public Person(String name, int age){System.out.println(name+".."+age);}public String getName(){return "zc in method";}public void getNothing(){System.out.println(name);}public void getNothing(int age){System.out.println(name + ": "+age);}}


package info.dyndns.oszc.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import org.junit.Test;public class TestDemo {@Testpublic void Test1() throws Exception {/** *  * 测试调用无参构造函数 * 第一步,获得class的字节码 * 第二部,调用getConstructor方法获得构造函数,其中null代表无参构造函数 * 第三部,利用构造器实例化,因为是无参的所以也传null作为参数 */Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Constructor c = clazz.getConstructor(null);c.newInstance(null);/* * output: public Person() */}// public Person(String name, int age)@Testpublic void Test2() throws Exception {/** * 测试调用有参构造函数 * 不同点在于 调用getConstructor是必须传入 参数的字节码 比如: * public Person(String name, int age)构造函数 * 需要String.class,int.class传入 也就是 getConstructor(String.class, int.class) * 最后在调用newInstance方法时传入相应的实参 * newInstance方法返回的是Object类型, */Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Constructor c = clazz.getConstructor(String.class, int.class);Person p = (Person) c.newInstance("zc", 27);System.out.println(p.getName());/** * output: * zc..27 * zc in method */}@SuppressWarnings("unchecked")@Testpublic void Test3() throws Exception {/** * 下面演示了如何调用类中的方法 * getMethod方法需要传入 方法名誉 ,参数类型的字节码,如果无无参则为null * 然后调用invoke方法,第一个参数代表某个类的实例,第二个则是参数 *  */Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Constructor<Person> c = clazz.getConstructor(String.class);Person p = c.newInstance("mike");Method method = clazz.getMethod("getNothing", null);method.invoke(p, null);/* * output: * public Person(String name) * mike */}@Testpublic void Test4() throws Exception {/** * 同test3()所示 * 这里的参数类型为int 所以多传入 int.class代表型参列表 * invoke传入相应的实参 28 */Person person = new Person();Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Constructor<Person> c = clazz.getConstructor(String.class);Person p = c.newInstance("mike");Method method = clazz.getMethod("getNothing", int.class);method.invoke(person, 28);/* * output: * public Person() * public Person(String name) * null: 28 */}@Testpublic void Test5() throws Exception {//Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Class clazz = Class.forName("info.dyndns.oszc.reflection.TestDemo");Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {Class[] types =method.getParameterTypes() ;StringBuilder sb = new StringBuilder();for (Class type:types){sb.append(type.getName()+",");}if(sb.length()!=0)sb.deleteCharAt(sb.length()-1);System.out.println(Modifier.toString(method.getModifiers())+" "+method.getReturnType().getName()+" "+method.getName()+" ("+sb.toString()+")");/* * output: * public void Test4 () * public void Test3 () * public void Test5 () * public void Test2 () * public void Test1 () * public void Test6 () * */}}@Testpublic void Test6() throws Exception {/** * 反射main方法  *  */Class clazz = Class.forName("info.dyndns.oszc.reflection.Person");Constructor<Person> c = clazz.getConstructor(String.class);Person p = c.newInstance("mike");Method method = clazz.getMethod("main", String[].class);//method.invoke(null, new String[]{"a","b"}); //会出现 IllegallArgumentException:wrong number of argumens异常//因为为了兼容1.4里面没有可变参数列表,所以所有的数组会被拆分,也就成了main(String a, String b)//所以抛出了异常,一下传入了一个Object的数组,他满足String[]类型,又可以被拆出正确的类型method.invoke(null, new Object[]{new String[]{"in","main"}});//但是 在其他方法中这又不是个问题了!Method method2 = clazz.getMethod("getNothing", int[].class);method2.invoke(p,new int[]{1,2,3});//这里照样传了一个int[]数组,照理来说应该也出错,但他很识相的调用了正确的方法//method2.invoke(p, new Object[]{new int[]{1,2,3}});当然这样也是可以的/** * public Person(String name) * in * main * public static void main(String[] argc) * public void getNothing(int[] age) * 1  2  3   */}}


原创粉丝点击