Java中动态代理实现原理深究

一、前言

  笔者平时开发使用“动态代理”不多,最近在看设计模式的时候,“动态代理”又在面前晃了几次,所以这次想从源码的角度去分析动态代理的实现原理,以窥探其精妙~

二、正文

2.1 静态代理

   本文源码基于jdk1.6.0_33

   在正式剖析动态代理的源码之前,我们可以先来看看“静态代理”(就是我们普通的代理模式)的UML图:

  从上图可以看出,代理类“ProxySubject”和被代理类“RealSubject”实现相同接口,并且“ProxySubject”关联“RealSubject”,客户端调用的时候,实际是调用“ProxySubject”,然后“ProxySubject”调用“RealSubject”同名方法,方法的最终实现是由“RealSubject”提供,“ProxySubject”可以实现对“RealSubject”的访问控制,也可以对对应的方法进行“增强”。下面举个简单的例子说明一下:

// Subject 
public interface Subject {
    public void doSomething();
}

//ProxySubject 
public class ProxySubject implements Subject {
    private Subject realSubject = new RealSubject();
    @Override
    public void doSomething() {
        System.out.println("before doSomething~");
        realSubject.doSomething();
        System.out.println("after doSomething~");
    }

}

//RealSubject 
public class RealSubject implements Subject {

    @Override
    public void doSomething() {
        System.out.println("小杜比亚在写博客");
    }

}

//Client
public class Client {

    public static void main(String[] args) {
        Subject subject = new ProxySubject();
        subject.doSomething();
    }

}

//输出
before doSomething~
小杜比亚在写博客
after doSomething~

  那么动态代理和这个静态代理有什么区别?这就体现在一个“动”字,从上面的代码我们知道,静态代理的“代理类”是程序员写好的,而动态代理的“代理类”是在程序运行期间动态生成的~有些刚开始接触Java编程的读者可能会很好奇,Java的类可以动态生成?当然可以,我之前有篇关于“类”加载的博文:深入探讨Java类加载机制里面有写到,程序运行期间,类加载器会将java字节码文件加载进内存,这边的“加载”是从磁盘上加载,java程序只要字节码文件,至于你的来源(网络、或者按照字节码文件格式进行动态生成),人家是不管的。

  直接切入正题,“动态代理”中牵扯到两个类:java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy,我们先看下一个简单的动态代理例子:

 1 //Subject 
 2 package com.proxy.main;
 3 public interface Subject {
 4     public void doSomething();
 5 }
 6 
 7 //RealSubject 
 8 package com.proxy.main;
 9 public class RealSubject implements Subject {
10 
11     @Override
12     public void doSomething() {
13         System.out.println("小杜比亚还在写博客,有点儿想玩游戏了,坚持~");
14     }
15 }
16 
17 //ProxyHandler
18 package com.proxy.main;
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.Method;
21 
22 public class ProxyHandler implements InvocationHandler {
23     private Object proxiedObj;
24     public ProxyHandler(Object proxiedObj){
25         this.proxiedObj = proxiedObj;
26     }
27     /**
28      * @author caoyg
29      * @date 2017-05-06
30      * @description设置“被代理”对象
31      * @param proxiedObj
32      */
33     public void setProxiedObject(Object proxiedObj){
34         this.proxiedObj = proxiedObj;
35     }
36     @Override
37     public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
38         return method.invoke(proxiedObj, args);
39     }
40 
41 }
42 
43 //Client
44 package com.proxy.main;
45 import java.lang.reflect.Proxy;
46 
47 public class Client {
48 
49     public static void main(String[] args) {
50         Subject sb = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
51                                                       new Class[]{Subject.class} , 
52                                                       new ProxyHandler(new RealSubject()));
53         sb.doSomething();
54     }
55 
56 }
57 
58 //输出
59 小杜比亚还在写博客,有点儿想玩游戏了,坚持~

  上面代码第37行,invoke方法三个参数含义如下:

1 /**
2  该方法负责集中处理动态代理类上的所有方法调用。
3  第一个参数是动态生成的代理类实例,
4  第二个参数是被调用的方法对象
5  第三个方法是方法调用参数。
6  调用处理器根据这三个参数进行预处理或分派到委托类实例上执行
7 */
8 public Object invoke(Object proxy, Method method, Object[] args)
9     throws Throwable;

 

2.2 动态代理机制

  1、先创建一个InvocationHandler实现类,并且将需要“被代理”的对象传递给它(类似下面代码

  

2、Proxy通过方法newProxyInstance接收classLoader和一组interfaces(“被代理”对象实现的接口)以及InvocationHandler的实现类实例(以下简称“h”),通过classLoader和interfaces构造动态代理类的Class(下面代码是Proxy的源码部分

 1 Class cl = getProxyClass(loader, interfaces);
 2 ............
 3 public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)throws IllegalArgumentException
 4     {
 5         //......省略
 6     byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(proxyName, interfaces);
 7     try {
 8         proxyClass = defineClass0(loader, proxyName,
 9         proxyClassFile, 0, proxyClassFile.length);
10     } catch (ClassFormatError e) {
11         /*
12         * A ClassFormatError here means that (barring bugs in the
13         * proxy class generation code) there was some other
14         * invalid aspect of the arguments supplied to the proxy
15         * class creation (such as virtual machine limitations
16         * exceeded).
17         */
18         throw new IllegalArgumentException(e.toString());
19     }
20     //......省略
21 return proxyClass; 22 }

  3、Proxy通过反射机制,将传入的h作为参数,调用动态代理对应的构造函数,返回最终的动态代理实例

 

  在调用动态代理类的方法时,动态代理将方法的调用分派转发给InvocationHandler的invoke方法,InvocationHandler的invoke方法又将方法调用分派给它本身引用的“被代理”类对应的方法。

2.3 动态代理注意点

  1、包:代理接口都是public修饰的,则代理类被定义在顶层包(package为空),如果访问修饰符是默认(default),那么代理类被定义在该接口所在包下面

 1     /*
 2            * Record the package of a non-public proxy interface so that the
 3            * proxy class will be defined in the same package.  Verify that
 4            * all non-public proxy interfaces are in the same package.
 5            */
 6           for (int i = 0; i < interfaces.length; i++) {
 7               int flags = interfaces[i].getModifiers();
 8               if (!Modifier.isPublic(flags)) {
 9                  String name = interfaces[i].getName();
10                  int n = name.lastIndexOf('.');
11                  String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
12                  if (proxyPkg == null) {
13                    proxyPkg = pkg;
14                  } else if (!pkg.equals(proxyPkg)) {
15                    throw new IllegalArgumentException("non-public interfaces from different packages");
16                  }
17              }
18          }
19  
20          if (proxyPkg == null) {    // if no non-public proxy interfaces,
21            proxyPkg = "";        // use the unnamed package
22          }

  2、生成的代理类为public final,不能被继承

3、类名:格式是“$ProxyN”,N是逐一递增的数字,代表Proxy被第N次动态生成的代理类,要注意,对于同一组接口(接口的排列顺序也相同),不会重复创建动态代理类,而是返回一个先前已经创建并缓存了的代理类对象。提高了效率

1      /*
2          * Choose a name for the proxy class to generate.代理类类名生成规则
3          */
4         long num;
5         synchronized (nextUniqueNumberLock) {
6             num = nextUniqueNumber++;
7         }
8         String proxyName = proxyPkg + proxyClassNamePrefix + num;
 1 synchronized (cache) {
 2     /*
 3     * Note that we need not worry about reaping the cache for
 4     * entries with cleared weak references because if a proxy class
 5     * has been garbage collected, its class loader will have been
 6     * garbage collected as well, so the entire cache will be reaped
 7     * from the loaderToCache map.
 8     */
 9     do {
10         Object value = cache.get(key);
11         if (value instanceof Reference) {
12             proxyClass = (Class) ((Reference) value).get();
13         }
14         if (proxyClass != null) {
15             // proxy class already generated: return it
16             return proxyClass;
17         } else if (value == pendingGenerationMarker) {
18             // proxy class being generated: wait for it
19             try {
20                 cache.wait();
21             } catch (InterruptedException e) {
22                 /*
23                 * The class generation that we are waiting for should
24                 * take a small, bounded time, so we can safely ignore
25                 * thread interrupts here.
26                 */
27             }
28             continue;
29         } else {
30             /*
31             * No proxy class for this list of interfaces has been
32             * generated or is being generated, so we will go and
33             * generate it now. Mark it as pending generation.
34             */
35             cache.put(key, pendingGenerationMarker);
36             break;
37         }
38     } while (true);
39 }

  4、类继承关系

  

  Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。(也算是java动态代理的一处缺陷,java不支持多继承,所以无法实现对class的动态代理,只能对于Interface的代理,cglib解决了这个问题)而且该类还实现了其所代理的一组接口,这就是为什么它能够被安全地类型转换到其所代理的某接口的根本原因。

  5、代理类的根类 java.lang.Object 中有三个方法也同样会被分派到调用处理器的 invoke 方法执行,它们是 hashCode,equals 和 toString,代码在反编译中

1 //ProxyGenerator.class
2  private byte[] generateClassFile()
3   {
4     addProxyMethod(hashCodeMethod, Object.class);
5     addProxyMethod(equalsMethod, Object.class);
6     addProxyMethod(toStringMethod, Object.class);
7     .....................
8 }

 

2.4 Proxy源码分析

  主要关注一些静态变量和两个方法,我们先来看看Proxy中的静态变量:

 1     /** prefix for all proxy class names */
 2    //类名前缀
 3     private final static String proxyClassNamePrefix = "$Proxy";
 4 
 5     /** parameter types of a proxy class constructor */
 6    //proxy类构造函数的参数类型,这个在通过反射生成动态代理类的时候用到
 7     private final static Class[] constructorParams = { InvocationHandler.class };
 8 
 9     /** maps a class loader to the proxy class cache for that loader */
10     private static Map loaderToCache = new WeakHashMap();
11 
12     /** marks that a particular proxy class is currently being generated */
13     private static Object pendingGenerationMarker = new Object();
14 
15     /** next number to use for generation of unique proxy class names */
16     //下个proxy的序号
17     private static long nextUniqueNumber = 0;
18     private static Object nextUniqueNumberLock = new Object();
19 
20     /** set of all generated proxy classes, for isProxyClass implementation */
21     private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());
22 
23     /**
24      * the invocation handler for this proxy instance.
25      * @serial
26      */
27     protected InvocationHandler h;

  接下来是两个重要方法:getProxyClass和newProxyInstance,这个newProxyInstance就是我们在前面的动态代理实例里面直接使用的方法,这个方法调用getProxyClass获取动态代理类的Class对象,然后通过反射生成动态代理类实例并返回:

 1  public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
 2     {
 3     if (h == null) {
 4         throw new NullPointerException();
 5     }
 6 
 7     /*
 8      * Look up or generate the designated proxy class.
 9      */
10     //生成动态代理Class
11     Class cl = getProxyClass(loader, interfaces);
12 
13     /*
14      * Invoke its constructor with the designated invocation handler.
15      */
16     try {
17         Constructor cons = cl.getConstructor(constructorParams);
18         //通过反射生成动态代理类实例对象,并返回
19         return (Object) cons.newInstance(new Object[] { h });
20     } catch (NoSuchMethodException e) {
21         throw new InternalError(e.toString());
22     } catch (IllegalAccessException e) {
23         throw new InternalError(e.toString());
24     } catch (InstantiationException e) {
25         throw new InternalError(e.toString());
26     } catch (InvocationTargetException e) {
27         throw new InternalError(e.toString());
28     }
29     }

  在Proxy整个源码中,主要工作都集中在方法getProxyClass中:

  1 public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException
  2     {
  3     //接口数的限制
  4     if (interfaces.length > 65535) {
  5         throw new IllegalArgumentException("interface limit exceeded");
  6     }
  7 
  8     Class proxyClass = null;
  9 
 10     /* collect interface names to use as key for proxy class cache */
 11     String[] interfaceNames = new String[interfaces.length];
 12 
 13     Set interfaceSet = new HashSet();    // for detecting duplicates
 14     /*下面这个for循环做三项安全验证:
 15      *1、传入的所有接口是否对loader可见,如果不可见,抛出异常
 16      *2、传入的所有”接口“是否真的都是interface,如果不是,抛出异常
 17      *3、传入的所有接口是否有重复,如果有,抛出异常
 18      */
 19     for (int i = 0; i < interfaces.length; i++) {
 20         /*
 21          * Verify that the class loader resolves the name of this
 22          * interface to the same Class object.
 23          */
 24         String interfaceName = interfaces[i].getName();
 25         Class interfaceClass = null;
 26         try {
 27         interfaceClass = Class.forName(interfaceName, false, loader);
 28         } catch (ClassNotFoundException e) {
 29         }
 30         if (interfaceClass != interfaces[i]) {
 31         throw new IllegalArgumentException(
 32             interfaces[i] + " is not visible from class loader");
 33         }
 34 
 35         /*
 36          * Verify that the Class object actually represents an
 37          * interface.
 38          */
 39         if (!interfaceClass.isInterface()) {
 40         throw new IllegalArgumentException(
 41             interfaceClass.getName() + " is not an interface");
 42         }
 43 
 44         /*
 45          * Verify that this interface is not a duplicate.
 46          */
 47         if (interfaceSet.contains(interfaceClass)) {
 48         throw new IllegalArgumentException(
 49             "repeated interface: " + interfaceClass.getName());
 50         }
 51         interfaceSet.add(interfaceClass);
 52 
 53         interfaceNames[i] = interfaceName;
 54     }
 55 
 56     /*
 57      * Using string representations of the proxy interfaces as
 58      * keys in the proxy class cache (instead of their Class
 59      * objects) is sufficient because we require the proxy
 60      * interfaces to be resolvable by name through the supplied
 61      * class loader, and it has the advantage that using a string
 62      * representation of a class makes for an implicit weak
 63      * reference to the class.
 64      */
 65     //接口名称列表(List类型)
 66     Object key = Arrays.asList(interfaceNames);
 67 
 68     /*
 69      * Find or create the proxy class cache for the class loader.(查询或者创建代理类的缓存,缓存未找到或者已经失效,那么重新创建一个)
 70      */
 71     Map cache;
 72     synchronized (loaderToCache) {
 73         cache = (Map) loaderToCache.get(loader);
 74         if (cache == null) {
 75         cache = new HashMap();
 76         loaderToCache.put(loader, cache);
 77         }
 78         /*
 79          * This mapping will remain valid for the duration of this
 80          * method, without further synchronization, because the mapping
 81          * will only be removed if the class loader becomes unreachable.
 82          */
 83     }
 84 
 85     /*
 86      * Look up the list of interfaces in the proxy class cache using
 87      * the key.  This lookup will result in one of three possible
 88      * kinds of values:
 89      *     null, if there is currently no proxy class for the list of
 90      *         interfaces in the class loader,
 91      *     the pendingGenerationMarker object, if a proxy class for the
 92      *         list of interfaces is currently being generated,
 93      *     or a weak reference to a Class object, if a proxy class for
 94      *         the list of interfaces has already been generated.
 95      */
 96     synchronized (cache) {
 97         /*
 98          * Note that we need not worry about reaping the cache for
 99          * entries with cleared weak references because if a proxy class
100          * has been garbage collected, its class loader will have been
101          * garbage collected as well, so the entire cache will be reaped
102          * from the loaderToCache map.
103          */
104         do {
105         //接口名称列表作为key,查找代理类缓存中是否已经存在创建好的动态代理类
106         Object value = cache.get(key);
107         if (value instanceof Reference) {
108             proxyClass = (Class) ((Reference) value).get();
109         }
110         //代理类如果已经创建,直接返回
111         if (proxyClass != null) {
112             // proxy class already generated: return it
113             return proxyClass;
114         } else if (value == pendingGenerationMarker) {//动态代理类还处于创建状态,那么当前线程进入等待
115             // proxy class being generated: wait for it
116             try {
117             cache.wait();
118             } catch (InterruptedException e) {
119             /*
120              * The class generation that we are waiting for should
121              * take a small, bounded time, so we can safely ignore
122              * thread interrupts here.
123              */
124             }
125             continue;//被唤醒之后,进行第二次检查
126         } else {
127             /*
128              * No proxy class for this list of interfaces has been
129              * generated or is being generated, so we will go and
130              * generate it now.  Mark it as pending generation.
131              */
132             /*如果接口名称列表映射的动态代理类还未创建,那么将pendingGenerationMarker先设置到动态代理类的缓存中,
133              *作为key的映射,表示接下来准备要开始动态代理类的创建了,并且退出当前循环
134                              */
135             cache.put(key, pendingGenerationMarker);
136             break;
137         }
138         } while (true);
139     }
140 
141     try {
142         String proxyPkg = null;    // package to define proxy class in
143 
144         /*
145          * Record the package of a non-public proxy interface so that the
146          * proxy class will be defined in the same package.  Verify that
147          * all non-public proxy interfaces are in the same package.
148          */
149          /*接下来这个循环,就是生成动态代理类的包名。首先校验所有interface是否都是public类型,如果声明为
150                  *public的,那么动态代理类的包名为"",如果存在不止一个interface的接口声明为非public类型(不写修饰符的情况),
151          *那么,所有这些非public访问声明的接口必须在同一个包中,否则抛出错误;如果这些非public访问声明的接口都在同
152          *一个包中,那么动态代理类的包名和这些非public访问声明的接口的包名一致
153          */
154         for (int i = 0; i < interfaces.length; i++) {
155         int flags = interfaces[i].getModifiers();
156         if (!Modifier.isPublic(flags)) {
157             String name = interfaces[i].getName();
158             int n = name.lastIndexOf('.');
159             String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
160             if (proxyPkg == null) {
161             proxyPkg = pkg;
162             } else if (!pkg.equals(proxyPkg)) {
163             throw new IllegalArgumentException(
164                 "non-public interfaces from different packages");
165             }
166         }
167         }
168 
169         if (proxyPkg == null) {    // if no non-public proxy interfaces,
170         proxyPkg = "";        // use the unnamed package
171         }
172 
173         {
174         /*
175          * Choose a name for the proxy class to generate.
176          */
177         long num;
178         //生成下一个动态代理类的序号
179         synchronized (nextUniqueNumberLock) {
180             num = nextUniqueNumber++;
181         }
182         //动态代理类的类名:包名+proxyClassNamePrefix + num;
183         String proxyName = proxyPkg + proxyClassNamePrefix + num;
184         /*
185          * Verify that the class loader hasn't already
186          * defined a class with the chosen name.
187          */
188 
189         /*
190          * Generate the specified proxy class.
191          */
192         //这个方法别人说有点儿复杂,反编译进去看确实挺复杂,这边笔者解释不了,这边就是生成动态代理类的字节
193         byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(
194             proxyName, interfaces);
195         try {
196             proxyClass = defineClass0(loader, proxyName,
197             proxyClassFile, 0, proxyClassFile.length);
198         } catch (ClassFormatError e) {
199             /*
200              * A ClassFormatError here means that (barring bugs in the
201              * proxy class generation code) there was some other
202              * invalid aspect of the arguments supplied to the proxy
203              * class creation (such as virtual machine limitations
204              * exceeded).
205              */
206             throw new IllegalArgumentException(e.toString());
207         }
208         }
209         // add to set of all generated proxy classes, for isProxyClass
210         proxyClasses.put(proxyClass, null);
211 
212     } finally {
213         /*
214          * We must clean up the "pending generation" state of the proxy
215          * class cache entry somehow.  If a proxy class was successfully
216          * generated, store it in the cache (with a weak reference);
217          * otherwise, remove the reserved entry.  In all cases, notify
218          * all waiters on reserved entries in this cache.
219          */
220         synchronized (cache) {
221         if (proxyClass != null) {
222             /*如果动态代理类创建成功,那么将动态代理类缓存中key对应的值更新成new WeakReference(proxyClass),原先
223              *设置的是pendingGenerationMarker
224              */
225             cache.put(key, new WeakReference(proxyClass));
226         } else {
227             //如果创建不成功,那么将key对应的映射移除
228             cache.remove(key);
229         }
230         //不管创建成功不成功,将阻塞在代理类缓存上面的线程唤醒
231         cache.notifyAll();
232         }
233     }
234     return proxyClass;
235     }

  以上内容已经大致将动态代理的内部实现交代清楚,下面的程序将动态代理的实例写入class文件,然后反编译出来看下,动态代理类的实例到底长什么样:

  生成动态代理类的Class文件代码:

 1 package com.proxy.main;
 2 
 3 import java.io.FileOutputStream;
 4 import java.lang.reflect.Proxy;
 5 
 6 import sun.misc.ProxyGenerator;
 7 
 8 public class Client {
 9 
10     public static void main(String[] args) {
11         Subject sb = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
12                                                       new Class[]{Subject.class} , 
13                                                       new ProxyHandler(new RealSubject()));
14         sb.doSomething();
15         createProxyClassFile();
16     }
17     
18     public static void createProxyClassFile(){
19         try{
20             String proxyName = "MyProxy";
21             byte[] data = ProxyGenerator.generateProxyClass(proxyName, new Class[]{Subject.class});
22             FileOutputStream out = new FileOutputStream( proxyName + ".class" );   
23             out.write(data);   
24             out.close();
25         }
26         catch(Exception e){
27             e.printStackTrace();
28         }
29     }
30 
31 }

  动态代理类反编译出来的代码:

  1 //因为传进去的interface数据中,所有interface的声明都是public,所以,动态代理类的包名为""
  2 import com.proxy.main.Subject;
  3 import java.lang.reflect.InvocationHandler;
  4 import java.lang.reflect.Method;
  5 import java.lang.reflect.Proxy;
  6 import java.lang.reflect.UndeclaredThrowableException;
  7 //继承自Proxy
  8 public final class MyProxy extends Proxy
  9   implements Subject
 10 {
 11   private static Method m1;
 12   private static Method m0;
 13   private static Method m3;
 14   private static Method m2;
 15 
 16   public MyProxy(InvocationHandler paramInvocationHandler)
 17     throws 
 18   {
 19     super(paramInvocationHandler);
 20   }
 21 
 22   public final boolean equals(Object paramObject)
 23     throws 
 24   {
 25     try
 26     {
 27       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 28     }
 29     catch (RuntimeException localRuntimeException)
 30     {
 31       throw localRuntimeException;
 32     }
 33     catch (Throwable localThrowable)
 34     {
 35     }
 36     throw new UndeclaredThrowableException(localThrowable);
 37   }
 38 
 39   public final int hashCode()
 40     throws 
 41   {
 42     try
 43     {
 44       return ((Integer)this.h.invoke(this, m0, null)).intValue();
 45     }
 46     catch (RuntimeException localRuntimeException)
 47     {
 48       throw localRuntimeException;
 49     }
 50     catch (Throwable localThrowable)
 51     {
 52     }
 53     throw new UndeclaredThrowableException(localThrowable);
 54   }
 55 
 56   public final void doSomething()
 57     throws 
 58   {
 59     try
 60     {
 61       this.h.invoke(this, m3, null);
 62       return;
 63     }
 64     catch (RuntimeException localRuntimeException)
 65     {
 66       throw localRuntimeException;
 67     }
 68     catch (Throwable localThrowable)
 69     {
 70     }
 71     throw new UndeclaredThrowableException(localThrowable);
 72   }
 73 
 74   public final String toString()
 75     throws 
 76   {
 77     try
 78     {
 79       return (String)this.h.invoke(this, m2, null);
 80     }
 81     catch (RuntimeException localRuntimeException)
 82     {
 83       throw localRuntimeException;
 84     }
 85     catch (Throwable localThrowable)
 86     {
 87     }
 88     throw new UndeclaredThrowableException(localThrowable);
 89   }
 90 
 91   static
 92   {
 93     try
 94     {
 95       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
 96       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 97       m3 = Class.forName("com.proxy.main.Subject").getMethod("doSomething", new Class[0]);
 98       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 99       return;
100     }
101     catch (NoSuchMethodException localNoSuchMethodException)
102     {
103       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
104     }
105     catch (ClassNotFoundException localClassNotFoundException)
106     {
107     }
108     throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
109   }
110 }

三、链接

http://blog.csdn.net/scplove/article/details/52451899

http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

原文地址:https://www.cnblogs.com/xdouby/p/6790753.html