在Java中实现JDK动态代理的原理是什么(java,jdk,动态代理,编程语言)

时间:2024-04-29 20:39:30 作者 : 石家庄SEO 分类 : 编程语言
  • TAG :

一、什么是代理?

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理模式UML图:

在Java中实现JDK动态代理的原理是什么

简单结构示意图:

在Java中实现JDK动态代理的原理是什么

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

二、Java 动态代理类

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法

publicobjectinvoke(Objectobj,Methodmethod,Object[]args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h) :构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces) :获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤:

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2.创建被代理的类以及接口

3.通过Proxy的静态方法

newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理

4.通过代理调用方法

三、JDK的动态代理怎么使用?

1、需要动态代理的接口:

packagejiankunking;/***需要动态代理的接口*/publicinterfaceSubject{/***你好**@paramname*@return*/publicStringSayHello(Stringname);/***再见**@return*/publicStringSayGoodBye();}

2、需要代理的实际对象

packagejiankunking;/***实际对象*/publicclassRealSubjectimplementsSubject{/***你好**@paramname*@return*/publicStringSayHello(Stringname){return"hello"+name;}/***再见**@return*/publicStringSayGoodBye(){return"goodbye";}}

3、调用处理器实现类(有木有感觉这里就是传说中的AOP啊)

packagejiankunking;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;/***调用处理器实现类*每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象*/publicclassInvocationHandlerImplimplementsInvocationHandler{/***这个就是我们要代理的真实对象*/privateObjectsubject;/***构造方法,给我们要代理的真实对象赋初值**@paramsubject*/publicInvocationHandlerImpl(Objectsubject){this.subject=subject;}/***该方法负责集中处理动态代理类上的所有方法调用。*调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行**@paramproxy代理类实例*@parammethod被调用的方法对象*@paramargs调用参数*@return*@throwsThrowable*/publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//在代理真实对象前我们可以添加一些自己的操作System.out.println("在调用之前,我要干点啥呢?");System.out.println("Method:"+method);//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用ObjectreturnValue=method.invoke(subject,args);//在代理真实对象后我们也可以添加一些自己的操作System.out.println("在调用之后,我要干点啥呢?");returnreturnValue;}}

4、测试

packagejiankunking;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Proxy;/***动态代理演示*/publicclassDynamicProxyDemonstration{publicstaticvoidmain(String[]args){//代理的真实对象SubjectrealSubject=newRealSubject();/***InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发*其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.*即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法*/InvocationHandlerhandler=newInvocationHandlerImpl(realSubject);ClassLoaderloader=realSubject.getClass().getClassLoader();Class[]interfaces=realSubject.getClass().getInterfaces();/***该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例*/Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);System.out.println("动态代理对象的类型:"+subject.getClass().getName());Stringhello=subject.SayHello("jiankunking");System.out.println(hello);//Stringgoodbye=subject.SayGoodBye();//System.out.println(goodbye);}}

5、输出结果如下:

演示demo下载地址:http://xiazai.jb51.net/201707/yuanma/DynamicProxyDemo(jb51.net).rar

四、动态代理怎么实现的?

从使用代码中可以看出,关键点在:

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);

通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。

也就是说,当代码执行到:

subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?

=======横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论============

以下代码来自:JDK1.8.0_92

既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?

/***Returnsaninstanceofaproxyclassforthespecifiedinterfaces*thatdispatchesmethodinvocationstothespecifiedinvocation*handler.**<p>{@codeProxy.newProxyInstance}throws*{@codeIllegalArgumentException}forthesamereasonsthat*{@codeProxy.getProxyClass}does.**@paramloadertheclassloadertodefinetheproxyclass*@paraminterfacesthelistofinterfacesfortheproxyclass*toimplement*@paramhtheinvocationhandlertodispatchmethodinvocationsto*@returnaproxyinstancewiththespecifiedinvocationhandlerofa*proxyclassthatisdefinedbythespecifiedclassloader*andthatimplementsthespecifiedinterfaces*@throwsIllegalArgumentExceptionifanyoftherestrictionsonthe*parametersthatmaybepassedto{@codegetProxyClass}*areviolated*@throwsSecurityExceptionifasecuritymanager,<em>s</em>,ispresent*andanyofthefollowingconditionsismet:*<ul>*<li>thegiven{@codeloader}is{@codenull}and*thecaller'sclassloaderisnot{@codenull}andthe*invocationof{@linkSecurityManager#checkPermission*s.checkPermission}with*{@codeRuntimePermission("getClassLoader")}permission*deniesaccess;</li>*<li>foreachproxyinterface,{@codeintf},*thecaller'sclassloaderisnotthesameasoran*ancestoroftheclassloaderfor{@codeintf}and*invocationof{@linkSecurityManager#checkPackageAccess*s.checkPackageAccess()}deniesaccessto{@codeintf};</li>*<li>anyofthegivenproxyinterfacesisnon-publicandthe*callerclassisnotinthesame{@linkplainPackageruntimepackage}*asthenon-publicinterfaceandtheinvocationof*{@linkSecurityManager#checkPermissions.checkPermission}with*{@codeReflectPermission("newProxyInPackage.{packagename}")}*permissiondeniesaccess.</li>*</ul>*@throwsNullPointerExceptionifthe{@codeinterfaces}array*argumentoranyofitselementsare{@codenull},or*iftheinvocationhandler,{@codeh},is*{@codenull}*/@CallerSensitivepublicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException{//检查h不为空,否则抛异常Objects.requireNonNull(h);finalClass<?>[]intfs=interfaces.clone();finalSecurityManagersm=System.getSecurityManager();if(sm!=null){checkProxyAccess(Reflection.getCallerClass(),loader,intfs);}/**获得与指定类装载器和一组接口相关的代理类类型对象*/Class<?>cl=getProxyClass0(loader,intfs);/**通过反射获取构造函数对象并生成代理类实例*/try{if(sm!=null){checkNewProxyPermission(Reflection.getCallerClass(),cl);}//获取代理对象的构造方法(也就是$Proxy0(InvocationHandlerh))finalConstructor<?>cons=cl.getConstructor(constructorParams);finalInvocationHandlerih=h;if(!Modifier.isPublic(cl.getModifiers())){AccessController.doPrivileged(newPrivilegedAction<Void>(){publicVoidrun(){cons.setAccessible(true);returnnull;}});}//生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法returncons.newInstance(newObject[]{h});}catch(IllegalAccessException|InstantiationExceptione){thrownewInternalError(e.toString(),e);}catch(InvocationTargetExceptione){Throwablet=e.getCause();if(tinstanceofRuntimeException){throw(RuntimeException)t;}else{thrownewInternalError(t.toString(),t);}}catch(NoSuchMethodExceptione){thrownewInternalError(e.toString(),e);}}

我们再进去getProxyClass0方法看一下:

/***Generateaproxyclass.MustcallthecheckProxyAccessmethod*toperformpermissionchecksbeforecallingthis.*/privatestaticClass<?>getProxyClass0(ClassLoaderloader,Class<?>...interfaces){if(interfaces.length>65535){thrownewIllegalArgumentException("interfacelimitexceeded");}//Iftheproxyclassdefinedbythegivenloaderimplementing//thegiveninterfacesexists,thiswillsimplyreturnthecachedcopy;//otherwise,itwillcreatetheproxyclassviatheProxyClassFactoryreturnproxyClassCache.get(loader,interfaces);}

真相还是没有来到,继续,看一下proxyClassCache

/***acacheofproxyclasses*/privatestaticfinalWeakCache<ClassLoader,Class<?>[],Class<?>>proxyClassCache=newWeakCache<>(newKeyFactory(),newProxyClassFactory());

奥,原来用了一下缓存啊

那么它对应的get方法啥样呢?

/***Look-upthevaluethroughthecache.Thisalwaysevaluatesthe*{@codesubKeyFactory}functionandoptionallyevaluates*{@codevalueFactory}functionifthereisnoentryinthecacheforgiven*pairof(key,subKey)ortheentryhasalreadybeencleared.**@paramkeypossiblynullkey*@paramparameterparameterusedtogetherwithkeytocreatesub-keyand*value(shouldnotbenull)*@returnthecachedvalue(nevernull)*@throwsNullPointerExceptionif{@codeparameter}passedinor*{@codesub-key}calculatedby*{@codesubKeyFactory}or{@codevalue}*calculatedby{@codevalueFactory}isnull.*/publicVget(Kkey,Pparameter){Objects.requireNonNull(parameter);expungeStaleEntries();ObjectcacheKey=CacheKey.valueOf(key,refQueue);//lazilyinstallthe2ndlevelvaluesMapfortheparticularcacheKeyConcurrentMap<Object,Supplier<V>>valuesMap=map.get(cacheKey);if(valuesMap==null){//putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入ConcurrentMap<Object,Supplier<V>>oldValuesMap=map.putIfAbsent(cacheKey,valuesMap=newConcurrentHashMap<>());if(oldValuesMap!=null){valuesMap=oldValuesMap;}}//createsubKeyandretrievethepossibleSupplier<V>storedbythat//subKeyfromvaluesMapObjectsubKey=Objects.requireNonNull(subKeyFactory.apply(key,parameter));Supplier<V>supplier=valuesMap.get(subKey);Factoryfactory=null;while(true){if(supplier!=null){//suppliermightbeaFactoryoraCacheValue<V>instanceVvalue=supplier.get();if(value!=null){returnvalue;}}//elsenosupplierincache//orasupplierthatreturnednull(couldbeaclearedCacheValue//oraFactorythatwasn'tsuccessfulininstallingtheCacheValue)//lazilyconstructaFactoryif(factory==null){factory=newFactory(key,parameter,subKey,valuesMap);}if(supplier==null){supplier=valuesMap.putIfAbsent(subKey,factory);if(supplier==null){//successfullyinstalledFactorysupplier=factory;}//elseretrywithwinningsupplier}else{if(valuesMap.replace(subKey,supplier,factory)){//successfullyreplaced//clearedCacheEntry/unsuccessfulFactory//withourFactorysupplier=factory;}else{//retrywithcurrentsuppliersupplier=valuesMap.get(subKey);}}}}

我们可以看到它调用了 supplier.get(); 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。

来瞅瞅,get里面又做了什么?

publicsynchronizedVget(){//serializeaccess//re-checkSupplier<V>supplier=valuesMap.get(subKey);if(supplier!=this){//somethingchangedwhilewewerewaiting://mightbethatwewerereplacedbyaCacheValue//orwereremovedbecauseoffailure->//returnnulltosignalWeakCache.get()toretry//theloopreturnnull;}//elsestillus(supplier==this)//createnewvalueVvalue=null;try{value=Objects.requireNonNull(valueFactory.apply(key,parameter));}finally{if(value==null){//removeusonfailurevaluesMap.remove(subKey,this);}}//theonlypathtoreachhereiswithnon-nullvalueassertvalue!=null;//wrapvaluewithCacheValue(WeakReference)CacheValue<V>cacheValue=newCacheValue<>(value);//tryreplacinguswithCacheValue(thisshouldalwayssucceed)if(valuesMap.replace(subKey,this,cacheValue)){//putalsoinreverseMapreverseMap.put(cacheValue,Boolean.TRUE);}else{thrownewAssertionError("Shouldnotreachhere");}//successfullyreplaceduswithnewCacheValue->returnthevalue//wrappedbyitreturnvalue;}}

发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法:

/***Afactoryfunctionthatgenerates,definesandreturnstheproxyclassgiven*theClassLoaderandarrayofinterfaces.*/privatestaticfinalclassProxyClassFactoryimplementsBiFunction<ClassLoader,Class<?>[],Class<?>>{//prefixforallproxyclassnamesprivatestaticfinalStringproxyClassNamePrefix="$Proxy";//nextnumbertouseforgenerationofuniqueproxyclassnamesprivatestaticfinalAtomicLongnextUniqueNumber=newAtomicLong();@OverridepublicClass<?>apply(ClassLoaderloader,Class<?>[]interfaces){Map<Class<?>,Boolean>interfaceSet=newIdentityHashMap<>(interfaces.length);for(Class<?>intf:interfaces){/**Verifythattheclassloaderresolvesthenameofthis*interfacetothesameClassobject.*/Class<?>interfaceClass=null;try{interfaceClass=Class.forName(intf.getName(),false,loader);}catch(ClassNotFoundExceptione){}if(interfaceClass!=intf){thrownewIllegalArgumentException(intf+"isnotvisiblefromclassloader");}/**VerifythattheClassobjectactuallyrepresentsan*interface.*/if(!interfaceClass.isInterface()){thrownewIllegalArgumentException(interfaceClass.getName()+"isnotaninterface");}/**Verifythatthisinterfaceisnotaduplicate.*/if(interfaceSet.put(interfaceClass,Boolean.TRUE)!=null){thrownewIllegalArgumentException("repeatedinterface:"+interfaceClass.getName());}}StringproxyPkg=null;//packagetodefineproxyclassinintaccessFlags=Modifier.PUBLIC|Modifier.FINAL;/**Recordthepackageofanon-publicproxyinterfacesothatthe*proxyclasswillbedefinedinthesamepackage.Verifythat*allnon-publicproxyinterfacesareinthesamepackage.*/for(Class<?>intf:interfaces){intflags=intf.getModifiers();if(!Modifier.isPublic(flags)){accessFlags=Modifier.FINAL;Stringname=intf.getName();intn=name.lastIndexOf('.');Stringpkg=((n==-1)?"":name.substring(0,n+1));if(proxyPkg==null){proxyPkg=pkg;}elseif(!pkg.equals(proxyPkg)){thrownewIllegalArgumentException("non-publicinterfacesfromdifferentpackages");}}}if(proxyPkg==null){//ifnonon-publicproxyinterfaces,usecom.sun.proxypackageproxyPkg=ReflectUtil.PROXY_PACKAGE+".";}/**Chooseanamefortheproxyclasstogenerate.*/longnum=nextUniqueNumber.getAndIncrement();StringproxyName=proxyPkg+proxyClassNamePrefix+num;/**Generatethespecifiedproxyclass.*/byte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces,accessFlags);try{returndefineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);}catch(ClassFormatErrore){/**AClassFormatErrorheremeansthat(barringbugsinthe*proxyclassgenerationcode)therewassomeother*invalidaspectoftheargumentssuppliedtotheproxy*classcreation(suchasvirtualmachinelimitations*exceeded).*/thrownewIllegalArgumentException(e.toString());}}}

通过看代码终于找到了重点:

//生成字节码byte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces,accessFlags);

那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:

packagejiankunking;importsun.misc.ProxyGenerator;importjava.io.File;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Proxy;/***动态代理演示*/publicclassDynamicProxyDemonstration{publicstaticvoidmain(String[]args){//代理的真实对象SubjectrealSubject=newRealSubject();/***InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发*其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.*即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法*/InvocationHandlerhandler=newInvocationHandlerImpl(realSubject);ClassLoaderloader=handler.getClass().getClassLoader();Class[]interfaces=realSubject.getClass().getInterfaces();/***该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例*/Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);System.out.println("动态代理对象的类型:"+subject.getClass().getName());Stringhello=subject.SayHello("jiankunking");System.out.println(hello);//将生成的字节码保存到本地,createProxyClassFile();}privatestaticvoidcreateProxyClassFile(){Stringname="ProxySubject";byte[]data=ProxyGenerator.generateProxyClass(name,newClass[]{Subject.class});FileOutputStreamout=null;try{out=newFileOutputStream(name+".class");System.out.println((newFile("hello")).getAbsolutePath());out.write(data);}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}finally{if(null!=out)try{out.close();}catch(IOExceptione){e.printStackTrace();}}}}

可以看一下这里代理对象的类型:

在Java中实现JDK动态代理的原理是什么

我们用jd-jui 工具将生成的字节码反编译:

importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.lang.reflect.UndeclaredThrowableException;importjiankunking.Subject;publicfinalclassProxySubjectextendsProxyimplementsSubject{privatestaticMethodm1;privatestaticMethodm3;privatestaticMethodm4;privatestaticMethodm2;privatestaticMethodm0;publicProxySubject(InvocationHandlerparamInvocationHandler){super(paramInvocationHandler);}publicfinalbooleanequals(ObjectparamObject){try{return((Boolean)this.h.invoke(this,m1,newObject[]{paramObject})).booleanValue();}catch(Error|RuntimeExceptionlocalError){throwlocalError;}catch(ThrowablelocalThrowable){thrownewUndeclaredThrowableException(localThrowable);}}publicfinalStringSayGoodBye(){try{return(String)this.h.invoke(this,m3,null);}catch(Error|RuntimeExceptionlocalError){throwlocalError;}catch(ThrowablelocalThrowable){thrownewUndeclaredThrowableException(localThrowable);}}publicfinalStringSayHello(StringparamString){try{return(String)this.h.invoke(this,m4,newObject[]{paramString});}catch(Error|RuntimeExceptionlocalError){throwlocalError;}catch(ThrowablelocalThrowable){thrownewUndeclaredThrowableException(localThrowable);}}publicfinalStringtoString(){try{return(String)this.h.invoke(this,m2,null);}catch(Error|RuntimeExceptionlocalError){throwlocalError;}catch(ThrowablelocalThrowable){thrownewUndeclaredThrowableException(localThrowable);}}publicfinalinthashCode(){try{return((Integer)this.h.invoke(this,m0,null)).intValue();}catch(Error|RuntimeExceptionlocalError){throwlocalError;}catch(ThrowablelocalThrowable){thrownewUndeclaredThrowableException(localThrowable);}}static{try{m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{Class.forName("java.lang.Object")});m3=Class.forName("jiankunking.Subject").getMethod("SayGoodBye",newClass[0]);m4=Class.forName("jiankunking.Subject").getMethod("SayHello",newClass[]{Class.forName("java.lang.String")});m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);return;}catch(NoSuchMethodExceptionlocalNoSuchMethodException){thrownewNoSuchMethodError(localNoSuchMethodException.getMessage());}catch(ClassNotFoundExceptionlocalClassNotFoundException){thrownewNoClassDefFoundError(localClassNotFoundException.getMessage());}}}

这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口

也就是说:

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);

这里的subject实际是这个类的一个实例,那么我们调用它的:

publicfinalStringSayHello(StringparamString)

就是调用我们定义的InvocationHandlerImpl的 invoke方法:

在Java中实现JDK动态代理的原理是什么

=======横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论================

五、结论

到了这里,终于解答了:

subject.SayHello("jiankunking")这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?

因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。

包含生成本地class文件的demo:

http://xiazai.jb51.net/201707/yuanma/DynamicProxyDemo2(jb51.net).rar

通过分析代码可以看出Java 动态代理,具体有如下四步骤:

  • 通过实现 InvocationHandler 接口创建自己的调用处理器;

  • 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

  • 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:在Java中实现JDK动态代理的原理是什么的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:java 线程之对象的同步和异步(实例讲解)下一篇:

3 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18