動態代理模式,前提還是代理模式,只是優化了靜態代理的一些不足。
比如,靜態代理在一對一關係出現時,創建的代理對象較多,代碼量也大,可維護性就會稍差,在一對多的代理關係出現是,可擴展性就更差了。
而動態代理,就是在使用時,纔去創建代理類和實例,這樣就可以通過一個動態代理類解決創建多個靜態代理的問題,更靈活了。
當然動態代理的缺點也是有的,就是相比靜態代理直接調用目標對象方法,動態代理效率會低,因爲它是通過反射機制,間接調用目標方法的。
所以,在討論動態代理前,需要先說說靜態代理,及反射。
先說反射,通常對一個類對象執行操作時,都要先知道它是什麼類,是做什麼的,然後去實例化 對象進行操作。
但是,反射則是一開始不知道要初始化的類是什麼,無法使用new關鍵字來創建對象。而是在運行時才知道要操作的類是什麼,可以在運行時獲取類的完整構造,並調用對應的方法,訪問屬性。
那反射跟運行時類信息(RTTI)有什麼區別呢?
運行時類型識別(Run-Time Type Identification),使得可以在程序運行時發現和使用類型信息。
Java有兩種方式可以讓我們在運行時識別對象和類的信息,一種是RTTI,它假定在編譯時已經知道了所有的類型;另一種就是反射,允許在運行時發現和使用類信息。
RTTI的基本使用
package rtti;
import java.util.Arrays;
import java.util.List;
public class ShapeRtti {
static abstract class Shape {
void draw() {
System.out.println(this + ".draw()");
}
abstract public String toString();
}
static class Circle extends Shape{
@Override
public String toString() {
return "Circle";
}
}
static class Square extends Shape{
@Override
public String toString() {
return "Square";
}
}
public static void main(String[] args) {
List<Shape> shapeList = Arrays.asList(new Circle(),new Square());
for (Shape shape : shapeList) {
shape.draw();
}
}
}
/*output*/
Circle.draw()
Square.draw()
在這個例子中,把Circle對象放入List<Shape>數組時會向上轉型,在向上轉型爲Shape時,也丟失了Shape對象的具體類型,對於數組來說,它們只是Shape類的對象。
當從數組取出元素時,會自動轉型會Shape(因爲List實際上把所有事物都當做Object持有),這就是RTTI最基礎的使用形式。在java中,多有的類型轉換都是在運行時進行正確性檢查的,也就是RTTI的含義,在運行時,識別一個對象的類型。
在說反射,Class類跟java.lang.reflect類庫,一起對反射的概念進行了支持,類庫包含了Field,Method,Constructor類,可以用Constructor創建新的對象,用get,set方法讀取修改Field對象關聯的字段,用invoke方法調用Method對象關聯的方法,用getField,getMethods,getContructor返回表示字段,方法,構造器的對象的數組。當通過反射與一個未知類型的對象打交道時,JVM只是簡單的檢查這個對象,看他屬於哪個特定的類,用他做事情前,必須先加載這個類的class對象,這個類的class文件對於jvm來說必須是可獲取的。
RTTI跟反射最根本的區別在於,對於RTTI來說,編譯器在編譯時打開和檢查.class文件,也就是說我們使用普通的方式調用對象的方法,但是對於反射來說,.class文件在編譯時是不可獲取的,而是要在運行時打開和檢查.class文件。
Class是一個類,封裝了當前對象所對應的類的信息
一個類中有屬性,方法,構造器等,比如說有一個Person類,一個Order類,一個Book類,這些都是不同的類,現在需要一個類,用來描述類,這就是Class,它應該有類名,屬性,方法,構造器等。Class是用來描述類的類。
Class類是一個對象照鏡子的結果,對象可以看到自己有哪些屬性,方法,構造器,實現了哪些接口等等
對於每個類而言,JRE 都爲其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個類的有關信息。
對象只能由系統建立對象,一個類(而不是一個對象)在 JVM 中只會有一個Class實例
獲取Class對象的三種方式
1.通過類名獲取 類名.class
2.通過對象獲取 對象名.getClass()
3.通過全類名獲取 Class.forName(全類名)
Class類的常用方法
然後說,靜態代理模式:爲其他對象提供一種代理,以控制對這個對象的訪問。
其中有抽象主題Subject,真實主題RealSubject,代理Proxy,
Subject定義了RealSubject,Proxy共用接口,在任何使用RealSubject的地方都可以使用Proxy。
RealSubject定義了Proxy代表的真實主題。
Proxy保存一個真實主題的引用,使得代理可以訪問真實主題,並提供了跟Subject相同的接口,這樣就可以代替真實主題。
RealSubject,Proxy跟Subject是繼承關係,而Proxy需要知道它代理的真實主題,所以跟RealSubject是關聯關係。
代理模式的實現代碼。
package simplePry;
public class SimpleProxyRun {
public SimpleProxyRun() {
}
public static void consumer(ProxyInterface pi) {
pi.doSomething();
pi.somethingElse("help me do.....");
}
public static void main(String[] args) {
consumer(new RealObject());
System.out.println("-----------------");
consumer(new SimpleProxy(new RealObject()));
}
}
package simplePry;
public class RealObject implements ProxyInterface {
public RealObject() {
System.out.println("realObject");
}
@Override
public void doSomething() {
System.out.println("realObject,do Something");
}
@Override
public void somethingElse(String args) {
System.out.println("realObject,somethingElse "+ args);
}
}
package simplePry;
public class SimpleProxy implements ProxyInterface {
private ProxyInterface mProxy;
public SimpleProxy(ProxyInterface proxy) {
mProxy = proxy;
System.out.println("SimpleProxy,mProxy="+mProxy);
}
@Override
public void doSomething() {
System.out.println("SimpleProxy,do Something");
mProxy.doSomething();
}
@Override
public void somethingElse(String args) {
System.out.println("SimpleProxy,somethingElse "+ args);
mProxy.somethingElse(args);
}
}
public class SimpleProxyRun {
public SimpleProxyRun() {
}
public static void consumer(ProxyInterface pi) {
pi.doSomething();
pi.somethingElse("help me do.....");
}
public static void main(String[] args) {
consumer(new RealObject());
System.out.println("-----------------");
consumer(new SimpleProxy(new RealObject()));
}
}
/*output*/
realObject
realObject,do Something
realObject,somethingElse help me do.....
-----------------
realObject
SimpleProxy,mProxy=simplePry.RealObject@15db9742
SimpleProxy,do Something
realObject,do Something
SimpleProxy,somethingElse help me do.....
realObject,somethingElse help me do.....
例子中,consumer接受的是ProxyInterface,它無法知道正在獲得的到底是RealObject還是SimpleProxy。但是SimpleProxy被插入到了客戶端和RealObject之間,所以他會執行操作,然後調用RealObject上相同的方法。
動態代理比靜態代理的思想又向前了一步,因爲他可以動態的創建代理並動態的處理對所代理方法的調用,在動態代理上所做的所有調用都會被重定向到單一的調用處理器上,它的任務就是揭示調用的類型,然後確定響應的對策。
動態代理中所謂的動態,是針對使用java代碼實際編寫了代理類的靜態代理而言的。它的優勢不在於省去了編寫代理類那一點工作量,而是實現了可以在原始類和接口還未知的時候,就確定代理類的代理行爲,當代理類與原始類脫離直接關係後,就可以靈活重用與不同的應用場景中。
下面用動態代理重寫上例。
package simpleDynamicPry;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----proxy:" + proxy.getClass() +
",method:" + method +
",args :" + args);
if (args != null) {
for (Object arg : args) {
System.out.println(" " + arg);
}
}
return method.invoke(proxied, args);
}
}
package simpleDynamicPry;
import java.lang.reflect.Proxy;
import simplePry.ProxyInterface;
import simplePry.RealObject;
public class SimpleDynamicProxy {
public SimpleDynamicProxy() {
}
public static void consumer(ProxyInterface pi) {
pi.doSomething();
pi.somethingElse(" dynamic proxy.");
}
public static void main(String[] args) {
RealObject real = new RealObject();
consumer(real);
//ProxyInterface.class.getClassLoader(),
//new Class[] {ProxyInterface.class},
ProxyInterface pi = (ProxyInterface)Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
new DynamicProxyHandler(real));
consumer(pi);
}
}
/*output*/
realObject
realObject,do Something
realObject,somethingElse dynamic proxy.
**********************
-----proxy:class com.sun.proxy.$Proxy0,method:public abstract void simplePry.ProxyInterface.doSomething(),args :null
realObject,do Something
-----proxy:class com.sun.proxy.$Proxy0,method:public abstract void simplePry.ProxyInterface.somethingElse(java.lang.String),args :[Ljava.lang.Object;@6bc7c054
dynamic proxy.
realObject,somethingElse dynamic proxy.
通過靜態方法Proxy.newProxyInstance創建動態代理,需要一個類加載器,一個希望該代理實現的接口列表(是接口,不是類、抽象類),一個InvocationHandler接口的實現。動態代理可以將所有調用重定向到調用處理器,因此通常會向調用處理器的構造器傳遞一個真實對象的引用,使得調用處理器在執行其中介任務時,可以將請求轉發。
這個Proxy.newProxyInstance()方法,返回的是一個實現了ProxyInterface接口,並且代理了RealObject實例行爲的對象。
最後,動態代理的實現原理。
在動態代理的例子中,真實的代理類,代理對象,並沒有看到它的class對象,那麼jdk內部是怎麼實現的呢?
通常,在jdk中,一個類的使用這樣的:
- 寫一個java源文件,
- 編譯成.class文件,
- Jvm通過類加載器生成一個Class對象,
- 通過Class對象,獲取到實例對象,
對於動態代理,沒有看到些java源文件的過程,也就是說動態代理類,沒有.class文件。
查看例子生成的class文件,也只看到:
DynamicProxyHandler.class
SimpleDynamicProxy.class
單步debug,可以看到
ProxyInterface pi = (ProxyInterface)Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
new DynamicProxyHandler(real));
這句代碼創建的對象是:$Proxy0,
這個類我們沒有寫過,在例子的輸出目錄中也沒有這個Proxy0這個類。
深入源碼:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
@Proxy.java {
// 前面的常規檢查,不去關注
// Class是對每個類的一個抽象,
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
//通過class拿到類的構造器,
final Constructor<?> cons = cl.getConstructor(constructorParams);
//返回類的一個實例。代理類實例的創建,就是由newInstance來負責的。
return cons.newInstance(new Object[]{h});
}
//Class<?> cl這個cl,很有可能就是我們沒有寫,由jdk內部幫我們創建的動態代理類。
//繼續跟進getProxyClass0,
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) @ Proxy.java {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//代理類,jdk是實現時,可能會做緩存
return proxyClassCache.get(loader, interfaces);
}
第一次用動態代理時,如果緩存裏沒有,怎麼處理的呢?
繼續看源碼:
public V get(K key, P parameter) @ WeakCache.java{
//這裏會從緩存獲取。
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
//這裏是真正創建代理類的地方,創建完成後,放入緩存。
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
}
分析:subKeyFactory.apply(key, parameter)
//這是一個泛型接口,
R apply(T t, U u)@BiFunction.java
在Proxy.java中有這個接口的具體實現。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> @ Proxy.java{
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
。。。
//不去關注別的,僅關注proxy類是怎麼創建的。
/*
* Choose a name for the proxy class to generate.
*/
//這裏可以看到,我們例子中創建的代理類$Proxy0,這個名字是怎麼來的,
//前綴:private static final String proxyClassNamePrefix = "$Proxy";
//num,是通過CAS的原子操作產生,換句話說,如果我們創建了2個動態代理類,第//二個應該就是$Proxy1
//需要提醒的是,這裏是android源碼庫下的實現,
//openjdk源碼的實現不太一樣,下面給出。
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
修改測試代碼,驗證第二個動態代理類是不是$Proxy1.
public interface ProxyInterface2 {
void doSomething();
void somethingElse(String args);
}
public class RealObject2 implements ProxyInterface2 {
public RealObject2() {
System.out.println("realObject");
}
@Override
public void doSomething() {
System.out.println("realObject,do Something");
}
@Override
public void somethingElse(String args) {
System.out.println("realObject,somethingElse "+ args);
}
}
public class SimpleDynamicProxy {
public SimpleDynamicProxy() {
}
public static void consumer(ProxyInterface pi) {
pi.doSomething();
pi.somethingElse(" dynamic proxy.");
}
public static void main(String[] args) {
RealObject real = new RealObject();
RealObject2 real_2 = new RealObject2();
consumer(real);
System.out.println("**********************");
//ProxyInterface.class.getClassLoader(),
//new Class[] {ProxyInterface.class},
ProxyInterface pi = (ProxyInterface)Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
new DynamicProxyHandler(real));
ProxyInterface2 pi_2 = (ProxyInterface2)Proxy.newProxyInstance(
real_2.getClass().getClassLoader(),
real_2.getClass().getInterfaces(),
new DynamicProxyHandler(real_2));
consumer(pi);
}
}
如上圖,通過debug可以看到第二個動態代理類名字是$Proxy1。
在看下openjdk源碼的實現。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
@ Proxy.java {
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
Jdk源碼中,代理類先是生成了一個字節數組,然後通過native方法創建了代理類的class,有字節數組,就可以通過流輸出到文件中,看看這個代理類長什麼樣。
但是android源碼中,沒有看到這個字節數組的生成,而是通過class_linker.cc中方法一步步生成,要輸出$proxy不是很容易。
generateProxy是native方法:
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
jobject loader, jobjectArray methods, jobjectArray throws) @ java_lang_reflect_Proxy.cc {
ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
soa, name, interfaces, loader, methods, throws));
}
下面用jdk的源碼實現,把$Proxy0的內容輸出到文件,看看這個類有哪些內容:
只要把源碼實現中:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
這個字節數組保存到文件即可。
public class ProxyUtils {
public static void generateClassFile(Class clazz,String proxyName){
/*ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);*/
byte[] proxyClassFile =ProxyGenerator.generateProxyClass(
proxyName, new Class[]{clazz});
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
out = new FileOutputStream(paths+proxyName+".class");
out.write(proxyClassFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class SimpleDynamicProxy {
public static void main(String[] args) {
RealObject real = new RealObject();
RealObject2 real_2 = new RealObject2();
consumer(real);
System.out.println("**********************");
//ProxyInterface.class.getClassLoader(),
//new Class[] {ProxyInterface.class},
ProxyInterface pi = (ProxyInterface)Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
new DynamicProxyHandler(real));
//添加生成$proxy0文件的調用
ProxyUtils.generateClassFile(real.getClass(),
pi.getClass().getSimpleName());
}
}
再次運行後,可以在項目的輸出目錄看到$Proxy0.class文件。
藉助反編譯工具JD-GUI,查看這個class文件
通過$Proxy0這個class文件,可以看出動態代理究竟是怎麼實現的。
這個代理類$Proxy0繼承自Proxy,實現了我們自定義的業務接口RealObject,所有的代理類都是繼承自Proxy。從下面Proxy.java的註釋也可以看出。
/**
* {@code Proxy} provides static methods for creating dynamic proxy
* classes and instances, and it is also the superclass of all
* dynamic proxy classes created by those methods.
*/
繼續看$Proxy0,
public final void doSomething()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
這個doSomething(),就是我們自定義的接口中的方法。
this.h.invoke(this, m3, null);
這是一個標準的反射機制中的調用。其中的h並不在$Proxy0中,而是在其父類Proxy.java中,
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
這個h就是在實現動態代理時,傳入的最後一個參數:
ProxyInterface pi = (ProxyInterface)Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
new DynamicProxyHandler(real));
所以$Proxy0中的invoke調用的就是DynamicProxyHandler.java中的invoke().。
其中的方法名m3,是誰呢?
Method m3就是通過反射拿到的業務類中定義的doSomething方法。所以invoke實際調用的就是業務類中實現的方法。
這個代理類的實現代碼其實很簡單,它爲接口中的每一個方法,及從java.lang.Object繼承下來的方法如equals(), hashcode()都生成了對應的實現,並且這些實現統一調用InvocationHandler的invoke方法去實現這些方法的內容,各個方法的區別只是傳入的參數和Method對象不同,所以無論調用動態代理的那個方法,實際都是執行InvocationHandler中的invoke的代碼邏輯。
要生成$Proxy0.class這個文件,還可以通過在main()中添加這個屬性:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
然後會在項目的根目錄下生成這個class文件。
附錄:$Proxy0.class
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import simplePry.RealObject;
public final class $Proxy0 extends Proxy
implements RealObject
{
private static Method m1;
private static Method m3;
private static Method m9;
private static Method m2;
private static Method m4;
private static Method m7;
private static Method m6;
private static Method m8;
private static Method m10;
private static Method m0;
private static Method m5;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void doSomething()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void notify()
throws
{
try
{
this.h.invoke(this, m9, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void somethingElse(String paramString)
throws
{
try
{
this.h.invoke(this, m4, new Object[] { paramString });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void wait(long paramLong)
throws InterruptedException
{
try
{
this.h.invoke(this, m7, new Object[] { Long.valueOf(paramLong) });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void wait(long paramLong, int paramInt)
throws InterruptedException
{
try
{
this.h.invoke(this, m6, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final Class getClass()
throws
{
try
{
return (Class)this.h.invoke(this, m8, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void notifyAll()
throws
{
try
{
this.h.invoke(this, m10, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void wait()
throws InterruptedException
{
try
{
this.h.invoke(this, m5, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("simplePry.RealObject").getMethod("doSomething", new Class[0]);
m9 = Class.forName("simplePry.RealObject").getMethod("notify", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("simplePry.RealObject").getMethod("somethingElse", new Class[] { Class.forName("java.lang.String") });
m7 = Class.forName("simplePry.RealObject").getMethod("wait", new Class[] { Long.TYPE });
m6 = Class.forName("simplePry.RealObject").getMethod("wait", new Class[] { Long.TYPE, Integer.TYPE });
m8 = Class.forName("simplePry.RealObject").getMethod("getClass", new Class[0]);
m10 = Class.forName("simplePry.RealObject").getMethod("notifyAll", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m5 = Class.forName("simplePry.RealObject").getMethod("wait", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}