Java反射机制学习笔记

Java反射机制简介

通过反射API可以获取程序在运行时刻的内部结构。反射API中提供的动态代理可以原生实现AOP中的方法拦截功能。通过反射获取到的Java类内部结构后再进行运用,和直接运用这个类效果相同,但额外的提供了运行时刻的灵活性。反射的最大一个弊端是性能比较差。相同的操作,用反射API所需的时间大概比直接的使用要慢一两个数量级。可以考虑在适当的时机来使用反射API。

基本用法

Java反射机制主要有两个作用。第一个主要作用是获取程序再运行时刻的内部结构。只需要少量的代码就能便利出一个Java类的内部结构来,其中包括构造方法、声明的域和定义的方法等。第二个主要的作用是在运行时刻对一个Java类进行操作。可以动态的创建一个Java类的对象,获取某个域的值以及调用某个方法。在Java源代码中编写的对类和对象的操作,都能通过反射来实现。

例如现在有一个简单的Java类:

class MyClass {public int count;public MyClass(int start) {count = start;}public void increase(int step) {count += step;}}

通过一般的做法和反射API来操作类及其对象都非常的简单。

MyClass myClass = new MyClass(0);myClass.increase(2);System.out.println(“Normal -> ” + myClass.count);try {Counstructor constructor = MyClass.class.getConstructor(int.class); //获取构造方法MyClass myClassReflect = constructor.newInstance(10); //创建对象Method method = MyClass.class.getMethod(“increase”, int.class); //获取方法Field field = MyClass.class.getField(“count”); //获取域,也就是变量System.out.println(“Reflect -> ” + field.getInt(myClassReflect)); //获取域的值} catch (Exception e) {e.printStackTrace();}

上面的例子中用到了四个反射的API:getConstructor()、newInstance()、getMethod()以及getField()。其中值得说明的是getMethod方法的一些注意事项。看下面的例子:

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;class Pet {private int age;private String name;public void eat() {System.out.println(“eat…..”);}private void sound() {System.out.println(“sound…..”);}}class Dogge extends Pet {private String gender;public void run() {System.out.println(“run…..”);}@Overridepublic void eat() {System.out.println(“eat meat…..”);}private void bark() {System.out.println(“woo…..”);}public Dogge() {}public Dogge(String gender) {this.gender = gender;}}public class JavaTest{public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException {Class<?> c1 = Dogge.class;Constructor<?>[] c = c1.getConstructors();Dogge d1 = (Dogge) c[1].newInstance(“heheda”);/*** eat方法是继承类重写之后的public方法* 可以通过reflect调用。*/Method eat = c1.getMethod(“eat”) ; //eat.invoke(d1);/*** sound方法是子类的private方法,通过普通的访问渠道调用不了* 但是通过reflect渠道(像这里直接reflect是不行的)能够调用,在下一个例子中将讲到。*///Method sound = c1.getDeclaredMethod(“sound”) ;//sound.invoke(d1);/*** bark方法在继承类中是private的* 这里如果用getMethod()方法来reflect该方法,是无法获取到的,原因在后面* 注意要用到setAccessible方法,因为是private方法,需要赋予权限。*/Method bark = c1.getDeclaredMethod(“bark”) ;bark.setAccessible(true);bark.invoke(d1);/*** run方法在继承类中,是public方法* 直接reflect即可*/Method run = c1.getMethod(“run”) ;run.invoke(d1);}}程序结果为: eat meat…..woo…..run…..

上面的例子说明了通过普通的reflect能够调用到子类public,父类public,private(注意这个要设置响应的权限setAccessible(true))。下面就说明下为什么父类的private方法不能直接getMethod方法获得,而是要通过getDeclaredMethod()方法去反射得到,先来看看官方文档中对getMethod()的介绍,:

/** * Returns a Method object that reflects the specified public * member method of the class or interface represented by this * Class object. The name parameter is a * String specifying the simple name of the desired method. The * parameterTypes parameter is an array of Class * objects that identify the method’s formal parameter types, in declared * order. If parameterTypes is null, it is * treated as if it were an empty array. * * Let C be the class represented by this object: * C is searched for any matching methods. If no matching *method is found, the algorithm of step 1 is invoked recursively on *the superclass of C. * If no method was found in step 1 above, the superinterfaces of C *are searched for a matching method. If any such method is found, it *is reflected. * * * To find a matching method in a class C:&nbsp; If C declares exactly one * public method with the specified name and exactly the same formal * parameter types, that is the method reflected. If more than one such * method is found in C, and one of these methods has a return type that is * more specific than any of the others, that method is reflected; * otherwise one of the methods is chosen arbitrarily. * */public Method getMethod(String name, Class<?>… parameterTypes)throws NoSuchMethodException, SecurityException {// be very careful not to change the stack depth of this// checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccesscheckMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());两种方法在这一行出现了分歧Method method = getMethod0(name, parameterTypes);if (method == null) {throw new NoSuchMethodException(getName() + “.” + name + argumentTypesToString(parameterTypes));}return method;}此处直接调用了native方法getMethod0方法,继续追踪代码就能发现:private Method getMethod0(String name, Class[] parameterTypes) {// Note: the intent is that the search algorithm this routine// uses be equivalent to the ordering imposed by// privateGetPublicMethods(). It fetches only the declared// public methods for each class, however, to reduce the// number of Method objects which have to be created for the// common case where the method being requested is declared in// the class which is being queried.Method res = null;// Search declared public methods关键地方出现了,和下面的getDeclaredMethod方法可以进行对比,问题出现在该方法第一个参数的不同,此处是true,getDeclaredMethod方法此处的参数为false.if ((res = searchMethods(privateGetDeclaredMethods(true),name,parameterTypes)) != null) {return res;}// Search superclass’s methodsif (!isInterface()) {Class c = getSuperclass();if (c != null) {if ((res = c.getMethod0(name, parameterTypes)) != null) {return res;}}}// Search superinterfaces’ methodsClass[] interfaces = getInterfaces();for (int i = 0; i < interfaces.length; i++) {Class c = interfaces[i];if ((res = c.getMethod0(name, parameterTypes)) != null) {return res;}}// Not foundreturn null;}如果可以,我真想和你一直旅行。或许是某个未开发的荒凉小岛,

Java反射机制学习笔记

相关文章:

你感兴趣的文章:

标签云: